通讯组件划分
1.NetworkClient(网络客户端用于客户端进行收发消息) & TcpSocketListener(用于服务器进行客户端监听、接受与响应消息)
2.封包处理器 PackageHandle 封包与协议的转换
3.消息分发器 MessageDistributer 若接收到网络客户端传来的消息,负责将这个消息分发到服务器各个模块中
4.消息分配处理 MessageDispatch 消息分发器,仅仅是将传过来的消息进行分发,并不会管消息是什么,至于哪一个消息分发给谁,是通过消息分配处理统筹的
NetClient实现细节
1.
public void Init(string serverIP, int port)//1.
{
this.address = new IPEndPoint(IPAddress.Parse(serverIP), port);//用指定的地址和端口号初始化IPEndPoint的新实例
}
public void Connect(int times = DEF_TRY_CONNECT_TIMES)//2.判断当前有无连接,或者是否已经实例化socket
{
if (this.connecting)
{
return;
}
if (this.clientSocket != null)
{
this.clientSocket.Close();
}
if (this.address == default(IPEndPoint))
{
throw new Exception("Please Init first.");
}
Debug.Log("DoConnect");
this.connecting = true;
this.lastSendTime = 0;
this.DoConnect();
}
void DoConnect()//3。以上都没有,真正开始连接
{
Debug.Log("NetClient.DoConnect on " + this.address.ToString());
try
{
if (this.clientSocket != null)
{
this.clientSocket.Close();
}
this.clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.clientSocket.Blocking = true;//阻塞到这里
Debug.Log(string.Format("Connect[{0}] to server {1}", this.retryTimes, this.address) + "\n");
IAsyncResult result = this.clientSocket.BeginConnect(this.address, null, null);//异步连接
bool success = result.AsyncWaitHandle.WaitOne(NetConnectTimeout);
if (success)
{
this.clientSocket.EndConnect(result);//结束挂起的连接请求
}
}
catch(SocketException ex)
{
if(ex.SocketErrorCode == SocketError.ConnectionRefused)
{
this.CloseConnection(NET_ERROR_FAIL_TO_CONNECT);
}
Debug.LogErrorFormat("DoConnect SocketException:[{0},{1},{2}]{3} ", ex.ErrorCode,ex.SocketErrorCode,ex.NativeErrorCode, ex.ToString());
}
catch (Exception e)
{
Debug.Log("DoConnect Exception:" + e.ToString() + "\n");
}
if (this.clientSocket.Connected)
{
this.clientSocket.Blocking = false;//停止阻塞
this.RaiseConnected(0, "Success");
}
else
{
this.retryTimes++;
if (this.retryTimes >= this.retryTimesTotal)
{
this.RaiseConnected(1, "Cannot connect to server");
}
}
this.connecting = false;
}
public void CloseConnection(int errCode)
{
Debug.LogWarning("CloseConnection(), errorCode: " + errCode.ToString());
this.connecting = false;
if (this.clientSocket != null)
{
this.clientSocket.Close();
}
//清空缓冲区
MessageDistributer.Instance.Clear();
this.sendQueue.Clear();
this.receiveBuffer.Position = 0;
this.sendBuffer.Position = sendOffset = 0;
}
public void Update()
{
if (!running)
{
return;
}
if (this.KeepConnect())//判断一下当前连接的状态
{
if (this.ProcessRecv())
{
if (this.Connected)
{
this.ProcessSend();
this.ProceeMessage();
}
}
}
}
bool KeepConnect()
{
if (this.connecting)
{
return false;
}
if (this.address == null)
return false;
if (this.Connected)
{
return true;
}
if (this.retryTimes < this.retryTimesTotal)
{
this.Connect();
}
return false;
}
bool ProcessRecv()
{
bool ret = false;
try
{
if (this.clientSocket.Blocking)
{
Debug.Log("this.clientSocket.Blocking = true\n");
}
bool error = this.clientSocket.Poll(0, SelectMode.SelectError);//判断是否有错误信息
if (error)
{
Debug.Log("ProcessRecv Poll SelectError\n");
this.CloseConnection(NET_ERROR_SEND_EXCEPTION);
return false;
}
ret = this.clientSocket.Poll(0, SelectMode.SelectRead);//如果没有错误,开始读取信息
if (ret)
{
int n = this.clientSocket.Receive(this.receiveBuffer.GetBuffer(), 0, this.receiveBuffer.Capacity, SocketFlags.None);//如果有数据,开始读取信息
if (n <= 0)
{
this.CloseConnection(NET_ERROR_ZERO_BYTE);
return false;
}
this.packageHandler.ReceiveData(this.receiveBuffer.GetBuffer(), 0, n);
}
}
catch (Exception e)
{
Debug.Log("ProcessReceive exception:" + e.ToString() + "\n");
this.CloseConnection(NET_ERROR_ILLEGAL_PACKAGE);
return false;
}
return true;
}
bool ProcessSend()
{
bool ret = false;
try
{
if (this.clientSocket.Blocking)
{
Debug.Log("this.clientSocket.Blocking = true\n");
}
bool error = this.clientSocket.Poll(0, SelectMode.SelectError);
if (error)
{
Debug.Log("ProcessSend Poll SelectError\n");
this.CloseConnection(NET_ERROR_SEND_EXCEPTION);
return false;
}
ret = this.clientSocket.Poll(0, SelectMode.SelectWrite);
if (ret)
{
//sendStream exist data
if (this.sendBuffer.Position > this.sendOffset)
{
int bufsize = (int)(this.sendBuffer.Position - this.sendOffset);
int n = this.clientSocket.Send(this.sendBuffer.GetBuffer(), this.sendOffset, bufsize, SocketFlags.None);
if (n <= 0)
{
this.CloseConnection(NET_ERROR_ZERO_BYTE);
return false;
}
this.sendOffset += n;
if (this.sendOffset >= this.sendBuffer.Position)//确保数据接受完全
{
this.sendOffset = 0;
this.sendBuffer.Position = 0;
this.sendQueue.Dequeue();//remove message when send complete
}
}
else//如果没有可写的数据,发送队列中的消息
{
//fetch package from sendQueue
if (this.sendQueue.Count > 0)
{
NetMessage message = this.sendQueue.Peek();
byte[] package = PackageHandler.PackMessage(message);
//byte[] package = PackageHandler.PackMessage(message);
this.sendBuffer.Write(package, 0, package.Length);
}
}
}
}
catch (Exception e)
{
Debug.Log("ProcessSend exception:" + e.ToString() + "\n");
this.CloseConnection(NET_ERROR_SEND_EXCEPTION);
return false;
}
return true;
}
void ProceeMessage()
{
MessageDistributer.Instance.Distribute();
}
封包处理器(PackageHandler数据处理)部分函数细节
- ReceiveData(byte[] data ,int offset, int count)
public void ReceiveData(byte[] data,int offset,int count)
{
if(stream.Position + count > stream.Capacity)
{
throw new Exception("PackageHandler write buffer overflow");
}
stream.Write(data, offset, count);//data 写入数据的数据缓冲区 offset 字节偏移量 count 最多写入的字节数
ParsePackage();
}
bool ParsePackage()
{
if (readOffset + 4 < stream.Position)
{
int packageSize = BitConverter.ToInt32(stream.GetBuffer(), readOffset);
if (packageSize + readOffset + 4 <= stream.Position)
{//包有效
SkillBridge.Message.NetMessage message = UnpackMessage(stream.GetBuffer(), this.readOffset + 4, packageSize);
if (message == null)
{
throw new Exception("PackageHandler ParsePackage faild,invalid package");
}
MessageDistributer<T>.Instance.ReceiveMessage(this.sender, message);
this.readOffset += (packageSize + 4);
return ParsePackage();
}
}
//未接收完/要结束了
if (this.readOffset > 0)
{
long size = stream.Position - this.readOffset;
if (this.readOffset < stream.Position)
{
Array.Copy(stream.GetBuffer(), this.readOffset, stream.GetBuffer(), 0, stream.Position - this.readOffset);
}
//Reset Stream
this.readOffset = 0;
stream.Position = size;
stream.SetLength(size);
}
return true;
}
public static SkillBridge.Message.NetMessage UnpackMessage(byte[] packet,int offset,int length)
{
SkillBridge.Message.NetMessage message = null;
using (MemoryStream ms = new MemoryStream(packet, offset, length))
{
message = ProtoBuf.Serializer.Deserialize<SkillBridge.Message.NetMessage>(ms);
}
return message;
}
消息分发器
使用Dictionary<string,Delegate> 进行存储与订阅
使用队列来存储消息
当一次性分发队列中所有消息的时候
public void Distribute()
{
if (this.messageQueue.Count == 0)
{
return;
}
while (this.messageQueue.Count > 0)
{
MessageArgs package = this.messageQueue.Dequeue();
if (package.message.Request != null)
MessageDispatch<T>.Instance.Dispatch(package.sender, package.message.Request);
if (package.message.Response != null)
MessageDispatch<T>.Instance.Dispatch(package.sender, package.message.Response);
}
}
消息分配处理
public class MessageDispatch<T> : Singleton<MessageDispatch<T>>
{
public void Dispatch(T sender, SkillBridge.Message.NetMessageResponse message)
{
if (message.mapEntitySync != null) { MessageDistributer<T>.Instance.RaiseEvent(sender, message.mapEntitySync); }
}
public void Dispatch(T sender, SkillBridge.Message.NetMessageRequest message)
{
if (message.mapTeleport != null) { MessageDistributer<T>.Instance.RaiseEvent(sender, message.mapTeleport); }
}
}
这里只列出了本人已经看懂的部分,剩下的可能以后追加。