导航:首页 > IDC知识 > photon服务器

photon服务器

发布时间:2020-11-01 01:14:56

1、想通过外网访问本地使用photon Server搭建的服务器怎么配置 win7,fast路由器 最好使用图片详解

首先要来排除电脑系统的问题,或源是硬件的问题。
然后就是检查IP设置的地方,DNS时候正确。
有的机子,之前设定的固定IP和DNS服务器和网关。
电信、长宽、铁通的DNS都会不同。
如果DNS不对,即使QQ等软件能正常上网,
也打不开网页。左键双击右下角的网络连接,
选择“常规”“属性”,双击“internet协议”
把“自动获得IP地址”和“自动获得DNS”都选中,
应用,就可以了。然后重启,连接上网

2、如果网络游戏运营商的服务器是光子服务器那游戏还坑钱吗?光子服务器能耗极小

玩儿游戏充值或者不充值是看自己意愿,再说了厂商研发的主要目的是赚钱。

3、photon可以做moba类游戏的服务器吗

服务器端源码:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

/**
*
* 文件名:ServerReceive.java
* 实现功能:作为服务器接收客户端发送的文件
*
* 具体实现过程:
* 1、建立SocketServer,等待客户端的连接
* 2、当有客户端连接的时候,按照双方的约定,这时要读取一行数据
* 其中保存客户端要发送的文件名和文件大小信息
* 3、根据文件名在本地创建文件,并建立好流通信
* 4、循环接收数据包,将数据包写入文件
* 5、当接收数据的长度等于提前文件发过来的文件长度,即表示文件接收完毕,关闭文件
* 6、文件接收工作结束

public class ServerReceive {

public static void main(String[] args) {

/**与服务器建立连接的通信句柄*/
ServerSocket ss = null;
Socket s = null;

/**定义用于在接收后在本地创建的文件对象和文件输出流对象*/
File file = null;
FileOutputStream fos = null;

/**定义输入流,使用socket的inputStream对数据包进行输入*/
InputStream is = null;

/**定义byte数组来作为数据包的存储数据包*/
byte[] buffer = new byte[4096 * 5];

/**用来接收文件发送请求的字符串*/
String comm = null;

/**建立socekt通信,等待服务器进行连接*/
try {
ss = new ServerSocket(4004);
s = ss.accept();
} catch (IOException e) {
e.printStackTrace();
}

/**读取一行客户端发送过来的约定信息*/
try {
InputStreamReader isr = new InputStreamReader(s.getInputStream());
BufferedReader br = new BufferedReader(isr);
comm = br.readLine();
} catch (IOException e) {
System.out.println("服务器与客户端断开连接");
}

/**开始解析客户端发送过来的请求命令*/
int index = comm.indexOf("/#");

/**判断协议是否为发送文件的协议*/
String xieyi = comm.substring(0, index);
if(!xieyi.equals("111")){
System.out.println("服务器收到的协议码不正确");
return;
}

/**解析出文件的名字和大小*/
comm = comm.substring(index + 2);
index = comm.indexOf("/#");
String filename = comm.substring(0, index).trim();
String filesize = comm.substring(index + 2).trim();

/**创建空文件,用来进行接收文件*/
file = new File(filename);
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
System.out.println("服务器端创建文件失败");
}
}else{
/**在此也可以询问是否覆盖*/
System.out.println("本路径已存在相同文件,进行覆盖");
}

/**【以上就是客户端代码中写到的服务器的准备部分】*/

/**
* 服务器接收文件的关键代码*/
try {
/**将文件包装到文件输出流对象中*/
fos = new FileOutputStream(file);
long file_size = Long.parseLong(filesize);
is = s.getInputStream();
/**size为每次接收数据包的长度*/
int size = 0;
/**count用来记录已接收到文件的长度*/
long count = 0;

/**使用while循环接收数据包*/
while(count < file_size){
/**从输入流中读取一个数据包*/
size = is.read(buffer);

/**将刚刚读取的数据包写到本地文件中去*/
fos.write(buffer, 0, size);
fos.flush();

/**将已接收到文件的长度+size*/
count += size;
System.out.println("服务器端接收到数据包,大小为" + size);
}

} catch (FileNotFoundException e) {
System.out.println("服务器写文件失败");
} catch (IOException e) {
System.out.println("服务器:客户端断开连接");
}finally{
/**
* 将打开的文件关闭
* 如有需要,也可以在此关闭socket连接
* */
try {
if(fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}//catch (IOException e)
}//finally

}//public static void main(String[] args)
}//public class ServerReceive

客户端源码:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;

/**
*
* 文件名:ClientSend.java
* 实现功能:作为客户端向服务器发送一个文件
*
* 具体实现过程:
* 1、建立与服务器端的连接,IP:127.0.0.1, port:4004
* 2、将文件的名字和大小通过自定义的文件传输协议,发送到服务器
* 3、循环读取本地文件,将文件打包发送到数据输出流中
* 4、关闭文件,结束传输
*
* */

public class ClientSend {

public static void main(String[] args) {

/**与服务器建立连接的通信句柄*/
Socket s = null;

/**定义文件对象,即为要发送的文件
* 如果使用绝对路径,不要忘记使用'/'和'\'的区别
* 具体区别,请读者自行查询
* */
File sendfile = new File("API.CHM");
/**定义文件输入流,用来打开、读取即将要发送的文件*/
FileInputStream fis = null;
/**定义byte数组来作为数据包的存储数据包*/
byte[] buffer = new byte[4096 * 5];

/**定义输出流,使用socket的outputStream对数据包进行输出*/
OutputStream os = null;

/**检查要发送的文件是否存在*/
if(!sendfile.exists()){
System.out.println("客户端:要发送的文件不存在");
return;
}

/**与服务器建立连接*/
try {
s = new Socket("127.0.0.1", 4004);
}catch (IOException e) {
System.out.println("未连接到服务器");
}

/**用文件对象初始化fis对象
* 以便于可以提取出文件的大小
* */
try {
fis = new FileInputStream(sendfile);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}

/**首先先向服务器发送关于文件的信息,以便于服务器进行接收的相关准备工作
* 具体的准备工作,请查看服务器代码。
*
* 发送的内容包括:发送文件协议码(此处为111)/#文件名(带后缀名)/#文件大小
* */
try {
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println("111/#" + sendfile.getName() + "/#" + fis.available());
ps.flush();
} catch (IOException e) {
System.out.println("服务器连接中断");
}

/**
* 此处睡眠2s,等待服务器把相关的工作准备好
* 也是为了保证网络的延迟
* 读者可自行选择添加此代码
* */
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}

/**之前的准备工作结束之后
* 下面就是文件传输的关键代码
* */
try {

/**获取socket的OutputStream,以便向其中写入数据包*/
os = s.getOutputStream();

/** size 用来记录每次读取文件的大小*/
int size = 0;

/**使用while循环读取文件,直到文件读取结束*/
while((size = fis.read(buffer)) != -1){
System.out.println("客户端发送数据包,大小为" + size);
/**向输出流中写入刚刚读到的数据包*/
os.write(buffer, 0, size);
/**刷新一下*/
os.flush();
}
} catch (FileNotFoundException e) {
System.out.println("客户端读取文件出错");
} catch (IOException e) {
System.out.println("客户端输出文件出错");
}finally{

/**
* 将打开的文件关闭
* 如有需要,也可以在此关闭socket连接
* */
try {
if(fis != null)
fis.close();
} catch (IOException e) {
System.out.println("客户端文件关闭出错");
}//catch (IOException e)
}//finally

}//public static void main(String[] args)
}//public class ClientSend

4、【Photon服务器】服务器端程序运行时报的错误Log,有大神知道都什么意思及解决办法吗?

PlayerHandler.cs:line 138,这里报错了,初步判断是数据传送的时候,解析出问题了

5、PhotonServer服务器连接mysql数据库报错,实在无力了,求大神!

本文将对NHibernate数据进行简单封装,方便在PhotonServer服务器中进行调用

[csharp] view plain copy

using NHibernate;  

using NHibernate.Cfg;  

using MyGameServer.Domain;  

using NHibernate.Criterion;  

using System.Collections.Generic;  

namespace MyGameServer.Helper  

{  

public static class NHibernateHelper  

{  

private static ISessionFactory sessionFactory = null;  

private static ISession session = null;  

public static ISession GetSession  

{  

get  

{  

if (sessionFactory == null)  

{  

Configuration cfg = new Configuration();  

//解析固定路径配置文件.cfg.xml  

cfg.Configure();  

//映射目标程序集 解析映射文件 Student.xml ......  

cfg.AddAssembly(typeof(Student).Assembly);  

//获取会话对象  

sessionFactory = cfg.BuildSessionFactory();  

}  

session = sessionFactory.OpenSession();  

return session;  

}  

private set { }  

}  

//添加行  

public static void AddData<T>(T t)  

{  

using (ISession session = GetSession)  

{  

using (ITransaction transaction=session.BeginTransaction())  

{  

GetSession.Save(t);  

transaction.Commit();  

}  

}  

}  

//添加列  

public static void RemoveData<T>(T t)  

{  

using (ISession session = GetSession)  

{  

using (ITransaction transaction = session.BeginTransaction())  

{  

GetSession.Delete(t);  

transaction.Commit();  

}  

}  

}  

//通过ID获取对象  

public static T GetDataById<T>(int id)  

{  

using (ISession session = GetSession)  

{  

using (ITransaction transaction = session.BeginTransaction())  

{  

T t = session.Get<T>(id);  

transaction.Commit();  

return t;  

}  

}  

}  

/// <summary>  

/// 通过名称获取对象  

/// </summary>  

/// <typeparam name="T">需要获取的对象</typeparam>  

/// <param name="dataBaseName">在数据库中的列名称</param>  

/// <param name="targetName">获取对象的目标名</param>  

/// <returns></returns>  

public static T GetDataByName<T>(string dataBaseName, string targetName)  

{  

using (ISession session = GetSession)  

{  

T t = session.CreateCriteria(typeof(T)).Add(Restrictions.Eq(dataBaseName, targetName)).UniqueResult<T>();  

return t;  

}  

}  

/// <summary>  

/// 得到表内的全部对象  

/// </summary>  

/// <typeparam name="T"></typeparam>  

/// <returns></returns>  

public static ICollection<T> GetAllUsers<T>()  

{  

using (ISession session = GetSession)  

{  

IList<T> ts = session.CreateCriteria(typeof(T)).List<T>();  

return ts;  

}  

}  

//查询是否有符合id和姓名相同的对象  

public static bool VerifyUser<T>(params object[] arg)  

{  

using (ISession session = GetSession)  

{  

T t = session  

.CreateCriteria(typeof(T))  

.Add(Restrictions.Eq(arg[0].ToString(), arg[1]))//类属性名 属性值  

.Add(Restrictions.Eq(arg[2].ToString(), arg[3]))  

.UniqueResult<T>();  

if (t == null)  

{  

return false;  

}  

return true;  

}  

}  

/// <summary>  

/// 更新数据表  

/// </summary>  

/// <typeparam name="T">数据表映射的对象</typeparam>  

/// <param name="t"></param>  

public static void UpdateData<T>(T t)  

{  

using (ISession session = GetSession)  

{  

using (ITransaction transaction=session.BeginTransaction())  

{  

session.Update(t);  

transaction.Commit();  

}  

}  

}  

}  

}  



在主函数调用

[csharp] view plain copy

using NHibernate;  

using NHibernate.Cfg;  

using LJL.Domain;  

using LJL.Helper;  

namespace LJL  

{  

class Program  

{  

static void Main(string[] args)  

{  

Student sd = new Student { mID = 6, mName = "小张", mScore = 10 };  

NHibernateHelper.AddData(sd);  

}  

}  

}  



运行程序,一切正常,打开SQLyog,在student数据表中添加一行数据

接下来就是在PhotonServer中调用,来实现与MySQL数据库交互

按图下将类、配置文件集成到类库中(注意需要修改下类和配置文件中的程序集及命名空间)


接下来就是在Unity3d游戏客户端中与PhotonServer通信进而访问本地数据库

在Unity3d客户端上创建UI(这里简单拖入输入框和按钮)

如下图创建脚本


我们的游戏有很多中请求(比如登入、注册请求等等)

所以都继承自BaseRequest

[csharp] view plain copy

using ExitGames.Client.Photon;  

using System.Collections;  

using System.Collections.Generic;  

using UnityEngine;  

public abstract class BaseRequest : MonoBehaviour  

{  

[HideInInspector]  

//该请求的操作类型  

public Collective.OperationMode operationMode = Collective.OperationMode.Default;  

public virtual void Start() { }  

public abstract void OnOperationRequest();  

public abstract void OnOperationResponse(OperationResponse operationResponse);  

}  



这里博主简单的做了一下登录请求

[csharp] view plain copy

using ExitGames.Client.Photon;  

using System.Collections;  

using System.Collections.Generic;  

using UnityEngine;  

using UnityEngine.UI;  

public class LoginRequest : BaseRequest  

{  

//用户名  

private InputField mInputName;  

//密码  

private InputField mInputPassword;  

public override void Start()  

{  

operationMode = Collective.OperationMode.LOGIN;  

GameContext.GetInstance.AddRequest(this);  

mInputName = GameObject.Find("IDInputField").GetComponent<InputField>();  

mInputPassword = GameObject.Find("NameInputField").GetComponent<InputField>();  

//登录按钮点击事件  

GameObject.Find("LoginButton").GetComponent<Button>().onClick.AddListener(() => { OnOperationRequest(); });  

}  

public override void OnOperationRequest()  

{  

GameContext.GetInstance.peer.OpCustom(  

(byte)this.operationMode,  

new Dictionary<byte, object> { { (byte)Collective.ParameterMode.NAME, mInputName.text }, { (byte)Collective.ParameterMode.PASSWORD, mInputPassword.text } },  

true  

);  

}  

public override void OnOperationResponse(OperationResponse operationResponse)  

{          

Collective.OperationResult resultCode = (Collective.OperationResult)operationResponse.ReturnCode;  

if (resultCode == Collective.OperationResult.SUCCESS)  

{  

//登录成功  

Debug.Log("用户登录成功");  

}  

else if(resultCode == Collective.OperationResult.FAIL)  

{  

//登录失败  

Debug.Log("登录失败");  

}  

}  

}  



最后附上上篇博文GameContext脚本,在这里有些地方发生了更新

[csharp] view plain copy

using System.Linq;  

using System.Collections.Generic;  

using UnityEngine;  

using UnityEngine.UI;  

using ExitGames.Client.Photon;  

public class GameContext : MonoBehaviour,IPhotonPeerListener  

{  

/// <summary>  

/// 存储操作类型与请求  

/// </summary>  

public Dictionary<Collective.OperationMode, BaseRequest> requestDic = new Dictionary<Collective.OperationMode, BaseRequest>();  

public PhotonPeer peer;  

private static GameContext _instance;  

public static GameContext GetInstance  

{  

get  

{  

if (_instance == null)  

{  

_instance = GameObject.Find("GameContext").GetComponent<GameContext>();  

}  

return _instance;  

}  

}  

public void DebugReturn(DebugLevel level, string message)  

{         

}  

//接收服务器发来的事件  

public void OnEvent(EventData eventData)  

{  

switch (eventData.Code)  

{  

case 0:  

//获取事件数据  

object value = eventData.Parameters.FirstOrDefault(q => q.Key == 1).Value;  

Debug.Log(value.ToString());  

break;  

default:  

break;  

}  

}  

//接收响应数据(客户端发送了请求)  

public void OnOperationResponse(OperationResponse operationResponse)  

{  

BaseRequest request = requestDic.FirstOrDefault(q => q.Key == (Collective.OperationMode)operationResponse.OperationCode).Value;  

if (request != null)  

{  

request.OnOperationResponse(operationResponse);  

}  

else  

{  

//获取响应数据失败  

Debug.LogError("获取响应数据失败");  

}  

}  

//连接状态发送改变  

public void OnStatusChanged(StatusCode statusCode)  

{  

Debug.Log("数据连接状态发生的改变:" + statusCode);  

}  

private void Start()  

{  

//传输协议UDP 、 通过Listener接收服务器端的响应  

peer = new PhotonPeer(this, ConnectionProtocol.Udp);  

//连接本地服务器  

peer.Connect("127.0.0.1:5055", "MYGameServer");  

}  

private void Update()  

{  

//和服务器实时保持数据连接  

peer.Service();                   

}  

private void OnDestroy()  

{  

if (peer != null && peer.PeerState == PeerStateValue.Connected)  

{  

//断开连接  

peer.Disconnect();  

}  

}  

public void AddRequest(BaseRequest request)  

{  

6、有人会用PhotonServer 作为unity 的服务器吗

photon 不是 网易那时候遗留下来的一个 服务端框架吗,那东西收费吧, 同步强连网还是自己写 soket 吧 比较稳妥,photon unity用的比较少吧

7、unity3d 网游服务器端如何选择

如果对楼主有帮助,给个采纳好不,谢谢啦

Photon和KBEngineunity3d是最适用Unity3d游戏开发的两个服务器引擎,但它们还是有区别的,只有清楚地了解区别在哪才能正确使用,下面简单描述下两者的共同点和不同点。

语言

对于大部分的程序员语言简直就是宗教信仰。

Photon使用C#开发,当然使用者也是用C#进行各类游戏功能开发。前后端同种语言,这对使用Unity3d游戏开发也有很大的好处。

KBEngine使用C++开发,逻辑开发是用python,也是很不错很快速的。

开源与收费情况

Photon是Exit Games公司的产品,不开源,有好多种收费模式,官网上可以看到。开发阶段可以用免费的license,后期可以看流量用户活跃度来选择付费模式。后续的支持,似乎是免费的,你可以选择邮件或是到论坛发帖求助,当然是E文。

KBEngine是国人开发,开源免费,但从官网上并没有看到商业使用的案例。有中文论坛,你可以在论坛上向开发者求助。

虽然两者的模式不同,但作为一个Unity3d游戏开发者,我们最希望的其实是把游戏引擎当作一个安全稳定的黑箱。

操作系统

之前说了Photon使用C#开发很自然的,配套的工具也是使用C#,比如最重要的PhotonControl。所以开发环境和生产环境最好都是windows。

虽然在跨平台上有mono,在服务器代码部分是系统无关的,但是不管你信不信,我是不信它的一套窗体工具也能运行在Linux下。反正,官网说法是,开发和生产环境都是用windows。

KBEngine建议开发环境选择Windows,生产环境选择linux。毕竟你总不希望开一组服务器打开9个Console窗体,一不小心把哪个点X了吧~

协议

Photon有自己的序列化反序列化方式,你也可以使用protobuf这类的来做应用层传输协议。

KBEngine在这方面表示不支持自定义协议,它帮你选择了有效的方法来处理,如果你习惯了他规定的方式,会喜欢上的。

看法

在功能上,我毫无疑问地更喜欢KBEngine,脚本化和自动持久化是极富魅力的功能。而Photon几乎没做这方面的功能,可能和老外的观念有关系。就目前我对两者功能的理解看来,Photon其实是个和SuperSocket差不多的东西,而SS是作为轻量级服务器框架存在的,Photon却是说自己是Unity3d游戏引擎,除去提供的MMO示例代码(未解读),没看到什么游戏引擎的魅力。

8、如何在android客户端连接电脑上搭建的Photon Server服务器端呢? 或者如何让另一

android客户端不来能直接与服务器数自据库连接,拿sqlserver来说,安装之后有几个G那么大,android程序是跑在手机上的,想让程序直接访问sqlserver,那手机需要非常大的内存。但是可以通过webservice这样一个桥梁来间接访问SQLServer。
即在服务器运行一个服务端程序,该服务端程序通过接收来自android客户端的指令,对数据库进行操作。客户端与服务端直接的数据传输主要通过http协议发送和接收json数据或者xml数据,服务端接收到客户端的json数据之后,进行json解析,再按一定的逻辑对数据库进行增、删、改、查。客户端的http请求可以通过 HttpClient类实现,在anddroid 4.0之后,客户端的网络请求已经不被允许在主线程中运行,所以题主还需注意另开启一个子线程进行网络请求。

9、有人会用PhotonServer 作为unity 的服务器吗

看英文是 证书获取 初始化 失败
可能是证源书有问题,其实我并不清楚
找到类似的文件
[email protected]
.license是证书的后缀,前面是你的注册邮箱找到一这个为结尾的文件就行
找到后,复制到你这个启动文件的目录。
友情提示:网上的教程已经过时,这个软件的一些构造函数已经变了,除非你能看懂官方文档,或者有人教你,不然,慎重选择

10、unity photon 能取代传统服务器吗

* 具体实现过程:
* 1、建立SocketServer,等待客户端的连接
* 2、当有客户端连接的时候,按照双方的约定,这时要读取一行数据
* 其中保存客户端要发送的文件名和文件大小信息
* 3、根据文件名在本地创建文件,并建立好流通信
* 4、循环接收数据包,将数据包写入文件
* 5、当接收数据的长度等于提前文件发过来的文件长度,即表示文件接收完毕,关闭文件
* 6、文件接收工作结束

public class ServerReceive {

public static void main(String[] args) {

/**与服务器建立连接的通信句柄*/
ServerSocket ss = null;
Socket s = null;

/**定义用于在接收后在本地创建的文件对象和文件输出流对象*/
File file = null;
FileOutputStream fos = null;

/**定义输入流,使用socket的inputStream对数据包进行输入*/
InputStream is = null;

/**定义byte数组来作为数据包的存储数据包*/
byte[] buffer = new byte[4096 * 5];

/**用来接收文件发送请求的字符串*/
String comm = null;

/**建立socekt通信,等待服务器进行连接*/
try {
ss = new ServerSocket(4004);
s = ss.accept();
} catch (IOException e) {
e.printStackTrace();
}

/**读取一行客户端发送过来的约定信息*/
try {
InputStreamReader isr = new InputStreamReader(s.getInputStream());
BufferedReader br = new BufferedReader(isr);
comm = br.readLine();
} catch (IOException e) {
System.out.println("服务器与客户端断开连接");
}

/**开始解析客户端发送过来的请求命令*/
int index = comm.indexOf("/#");

/**判断协议是否为发送文件的协议*/
String xieyi = comm.substring(0, index);
if(!xieyi.equals("111")){
System.out.println("服务器收到的协议码不正确");
return;
}

/**解析出文件的名字和大小*/
comm = comm.substring(index + 2);
index = comm.indexOf("/#");
String filename = comm.substring(0, index).trim();
String filesize = comm.substring(index + 2).trim();

/**创建空文件,用来进行接收文件*/
file = new File(filename);
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
System.out.println("服务器端创建文件失败");
}
}else{
/**在此也可以询问是否覆盖*/
System.out.println("本路径已存在相同文件,进行覆盖");
}

/**【以上就是客户端代码中写到的服务器的准备部分】*/

/**
* 服务器接收文件的关键代码*/
try {
/**将文件包装到文件输出流对象中*/
fos = new FileOutputStream(file);
long file_size = Long.parseLong(filesize);
is = s.getInputStream();
/**size为每次接收数据包的长度*/
int size = 0;
/**count用来记录已接收到文件的长度*/
long count = 0;

/**使用while循环接收数据包*/
while(count < file_size){
/**从输入流中读取一个数据包*/
size = is.read(buffer);

/**将刚刚读取的数据包写到本地文件中去*/
fos.write(buffer, 0, size);
fos.flush();

/**将已接收到文件的长度+size*/
count += size;
System.out.println("服务器端接收到数据包,大小为" + size);
}

} catch (FileNotFoundException e) {
System.out.println("服务器写文件失败");
} catch (IOException e) {
System.out.println("服务器:客户端断开连接");
}finally{
/**
* 将打开的文件关闭
* 如有需要,也可以在此关闭socket连接
* */
try {
if(fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}//catch (IOException e)
}//finally

}//public static void main(String[] args)
}//public class ServerReceive

客户端源码:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;

/**
*
* 文件名:ClientSend.java
* 实现功能:作为客户端向服务器发送一个文件
*
* 具体实现过程:
* 1、建立与服务器端的连接,IP:127.0.0.1, port:4004
* 2、将文件的名字和大小通过自定义的文件传输协议,发送到服务器
* 3、循环读取本地文件,将文件打包发送到数据输出流中
* 4、关闭文件,结束传输
*
* */

public class ClientSend {

public static void main(String[] args) {

/**与服务器建立连接的通信句柄*/
Socket s = null;

/**定义文件对象,即为要发送的文件
* 如果使用绝对路径,不要忘记使用'/'和'\'的区别
* 具体区别,请读者自行查询
* */
File sendfile = new File("API.CHM");
/**定义文件输入流,用来打开、读取即将要发送的文件*/
FileInputStream fis = null;
/**定义byte数组来作为数据包的存储数据包*/
byte[] buffer = new byte[4096 * 5];

/**定义输出流,使用socket的outputStream对数据包进行输出*/
OutputStream os = null;

/**检查要发送的文件是否存在*/
if(!sendfile.exists()){
System.out.println("客户端:要发送的文件不存在");
return;
}

/**与服务器建立连接*/
try {
s = new Socket("127.0.0.1", 4004);
}catch (IOException e) {
System.out.println("未连接到服务器");
}

/**用文件对象初始化fis对象
* 以便于可以提取出文件的大小
* */
try {
fis = new FileInputStream(sendfile);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}

/**首先先向服务器发送关于文件的信息,以便于服务器进行接收的相关准备工作
* 具体的准备工作,请查看服务器代码。
*
* 发送的内容包括:发送文件协议码(此处为111)/#文件名(带后缀名)/#文件大小
* */
try {
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println("111/#" + sendfile.getName() + "/#" + fis.available());
ps.flush();
} catch (IOException e) {
System.out.println("服务器连接中断");
}

/**
* 此处睡眠2s,等待服务器把相关的工作准备好
* 也是为了保证网络的延迟
* 读者可自行选择添加此代码
* */
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}

/**之前的准备工作结束之后
* 下面就是文件传输的关键代码
* */
try {

/**获取socket的OutputStream,以便向其中写入数据包*/
os = s.getOutputStream();

/** size 用来记录每次读取文件的大小*/
int size = 0;

/**使用while循环读取文件,直到文件读取结束*/
while((size = fis.read(buffer)) != -1){
System.out.println("客户端发送数据包,大小为" + size);
/**向输出流中写入刚刚读到的数据包*/
os.write(buffer, 0, size);
/**刷新一下*/
os.flush();
}
} catch (FileNotFoundException e) {
System.out.println("客户端读取文件出错");
} catch (IOException e) {
System.out.println("客户端输出文件出错");
}finally{

/**
* 将打开的文件关闭
* 如有需要,也可以在此关闭socket连接
* */
try {
if(fis != null)
fis.close();
} catch (IOException e) {
System.out.println("客户端文件关闭出错");
}//catch (IOException e)
}//finally

}//public static void main(String[] args)
}//public class ClientSend

与photon服务器相关的知识