using UnityEngine; using System.Collections; using System.Collections.Generic; using System; using System.Net; using System.Net.Sockets; using System.Text; using System.IO; namespace Engine.Net { /// 服务器类型 public enum ESockeType { /// 游戏服务器 Game = 0, } /// 服务器类型 public enum ESocketConnectType { /// 连接类型 TCP = 0, UDP = 1, } /// 客户端socket对象 public class NetSocket { /// 连接对象 public Socket mSocket = null; /// 接收数据的位置。 private int nRecvPos = 0; /// 保存接受到的数据 private byte[] arrRecvBuff; /// 接受到的消息 private Queue mQueueRecvMsg; /// 消息日志对象 public NetMsgLog netMsgLog = new NetMsgLog(); /// 对发送的优化,增加处理:多线程调用SendMsg时的处理,BeginSend和EndSend的串行处理,增加发送缓冲区 private System.Object mSendLock = new System.Object(); /// 需要发送的内容 private byte[] mSendBuff; /// 发送的长度 private int nSendBuffDataLen; /// 表示已经调用了BeginSend,正在等待结束 private bool bSendPending = false; /// 服务器类型 //public ESockeType socketType = ESockeType.Game; /// 连接类型 public ESocketConnectType socketConnectType = ESocketConnectType.TCP; /// 构造函数 public NetSocket(ESockeType type, ESocketConnectType connectType) { //socketType = type; socketConnectType = connectType; arrRecvBuff = new byte[NetMsg.MAX_MSG_LEN]; nRecvPos = 0; mQueueRecvMsg = new Queue(); mSendBuff = new byte[NetMsg.MAX_MSG_LEN]; nSendBuffDataLen = 0; } #region 创建和断开连接 /// 创建Socket连接 public bool Connect(string strIp, int nPort) { //如果存在连接线断开 if (mSocket != null) { DoDisconnect(false); } try { if(socketConnectType == ESocketConnectType.TCP) { mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); } else if(socketConnectType == ESocketConnectType.UDP) { mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); } CDebug.Log("Connect " + strIp + " "+nPort); mSocket.BeginConnect(strIp, nPort, new AsyncCallback(ConnectCallback), mSocket); //Debug.Log(mSocket.ReceiveBufferSize + " " + mSocket.SendBufferSize); mSocket.ReceiveBufferSize = 204800; mSocket.SendBufferSize = 204800; //Debug.Log(mSocket.ReceiveBufferSize + " " + mSocket.SendBufferSize); } catch (SocketException e) { SendDisconnectMsg(true); CDebug.LogError(e.Message); return false; } return true; } /// Socket连接完成 private void ConnectCallback(IAsyncResult ar) { try { Socket client = (Socket)ar.AsyncState; client.EndConnect(ar); nRecvPos = 0; if (!StartRecvMsg()) { DoDisconnect(); } SendConnectGSuccess(); } catch (SocketException e) { CDebug.LogError(e.Message); mSocket.Close(); mSocket = null; } } /// Socket对象是否连接中 public bool IsConnected() { return (mSocket == null) ? false : mSocket.Connected; } /// 发送Socket连接失败的消息 private void SendDisconnectMsg(bool bReceiveDisconnMsg = true) { if (bReceiveDisconnMsg == true) { NetMsg msg = new NetMsg(NetCode.MSG_CONE_CONNECT_FAIL); //msg.arrData.WriteInt((int)socketType); mQueueRecvMsg.Enqueue(msg); } } /// 服务器连接成功 private void SendConnectGSuccess() { NetMsg msg = new NetMsg(NetCode.MSG_CONE_CONNECT_SUCCESS); //msg.arrData.WriteInt((int)socketType); ; mQueueRecvMsg.Enqueue(msg); } #endregion #region 接受消息相关 /// 获得一个已经接受到的消息 public NetMsg RecvMsg() { if (mQueueRecvMsg.Count == 0) return null; NetMsg msg = null; try { msg = mQueueRecvMsg.Dequeue(); } catch { } return msg; } /// 开始接受消息 private bool StartRecvMsg() { if (mSocket == null) return false; try { SocketError err; mSocket.BeginReceive(arrRecvBuff, nRecvPos, arrRecvBuff.Length - nRecvPos, SocketFlags.None, out err, new AsyncCallback(RecvCallback), this); } catch { return false; } return true; } /// 消息接受完成 private void RecvCallback(IAsyncResult ar) { int nRecv = 0; try { if (mSocket != null) { SocketError err; nRecv = mSocket.EndReceive(ar, out err); } else { SendDisconnectMsg(); return; } } catch (System.Exception e) { //出现异常 #if UNITY_EDITOR CDebug.LogError("recv msg error "+ e.Message + e.StackTrace); #endif SendDisconnectMsg(); return; } //如果接受的字节数是0,断开连接 if (nRecv == 0) { DoDisconnect(true, "Common disconnect"); return; } //CDebug.Log("字节长度 " + nRecv); //追加接受的到字节 nRecvPos += nRecv; //循环读取接受到的全部消息内容 do { if (!IsConnected()) break; NetMsg msg = null; if (ParseMsg(ref arrRecvBuff, ref nRecvPos, ref msg)) { //添加接收时序 UpdateMsgResSequence(); //解析成功吧消息添加到队列中 mQueueRecvMsg.Enqueue(msg); //接受消息日志 netMsgLog.ResMessage(msg); } else { //解析失败 break; } } while (true); //继续挂起接收消息 StartRecvMsg(); } /// 解析消息 private bool ParseMsg(ref byte[] buff, ref int nLen, ref NetMsg msg) { //当前数据长度小于固定长度,返回失败 if (nLen < NetMsg.MIN_MSG_LEN) return false; msg = NetMsg.OnCreateNetMsg(buff); //获得当前消息的长度 int nMsgSize = msg.arrData.ReadInt(); //判断消息长度是否合法 if (nMsgSize < NetBytes.INT32_LEN || nMsgSize > NetMsg.MAX_MSG_LEN) { //消息长度非法,断开连接 DoDisconnect(true, "Invalid msg len " + nMsgSize); return false; } //如果当前消息不完整,失败 if (nLen < nMsgSize) { CDebug.Log("如果当前消息不完整 " + nLen + " " + nMsgSize); return false; } if (!msg.ReadMessage(buff, nMsgSize)) { RemoveBuff(ref buff, ref nLen, nMsgSize); CDebug.Log("读取失败 " + nLen + " " + nMsgSize); return false; } //清除该消息的缓冲区 RemoveBuff(ref buff, ref nLen, nMsgSize); return true; } /// 清理消息buff private void RemoveBuff(ref byte[] buff, ref int nLen, int nSize) { if (nSize <= nLen) { int nCopyLen = nLen - nSize; for (int i = 0; i < nCopyLen; ++i) { buff[i] = buff[i + nSize]; } nLen -= nSize; } } /// 断开连接 public void DoDisconnect(bool bReceiveDisconnMsg = true, string strReason = null) { if (!IsConnected()) { return; } if (!string.IsNullOrEmpty(strReason)) { CDebug.LogError("Disconnect connection: " + strReason); } if (mSocket != null) { SendDisconnectMsg(bReceiveDisconnMsg); CDebug.Log("尝试断开socket链接" + mSocket.Connected); try { mSocket.Disconnect(true); mSocket.Close(); } catch { CDebug.LogError("DisConnected"); } mSocket = null; nRecvPos = 0; } } /// 修改接受消息的消息时序 private void UpdateMsgResSequence() { //目前版本消息时序没有添加验证 } #endregion #region 发送消息相关 /// 发送消息 public bool SendMsg(NetMsg msg) { if (mSocket == null) return false; lock (mSendLock) { byte[] buff = null; buff = msg.FastPackMsg(); if (buff == null) return false; //修改发送消息的消息时序 UpdateMsgSendSequence(); int nNewSendBuffDataLen = nSendBuffDataLen + buff.Length; if (mSendBuff.Length < nNewSendBuffDataLen) { System.Array.Resize(ref mSendBuff, nNewSendBuffDataLen * 2); } System.Array.Copy(buff, 0, mSendBuff, nSendBuffDataLen, buff.Length); nSendBuffDataLen += buff.Length; //发送日志 netMsgLog.SendMessage(msg); SendDataInBuffer_inLock(); } return true; } /// 发送消息 private void SendDataInBuffer_inLock() { if (bSendPending) return; try { if (nSendBuffDataLen == 0) return; SocketError err; mSocket.BeginSend(mSendBuff, 0, nSendBuffDataLen, SocketFlags.None, out err, SendCallback, this); if (err != SocketError.Success && err != SocketError.WouldBlock) { DoDisconnect(true, "BeginSend error " + err.ToString()); return; } bSendPending = true; } catch (Exception e) { if (e is SocketException) { SocketException es = (SocketException)e; if (es.SocketErrorCode == SocketError.Success || es.SocketErrorCode == SocketError.WouldBlock) { return; } } DoDisconnect(true, "BeginSend excption: " + e.Message); return; } } /// 发送消息完成 private void SendCallback(IAsyncResult ar) { lock (mSendLock) { bSendPending = false; if (mSocket == null) return; try { SocketError err; int nSendLen = mSocket.EndSend(ar, out err); if (nSendLen <= 0) { if (err != SocketError.Success && err != SocketError.WouldBlock) { DoDisconnect(true, "EndSend error " + err.ToString()); } return; } RemoveBuff(ref mSendBuff, ref nSendBuffDataLen, nSendLen); if (nSendBuffDataLen > 0) { SendDataInBuffer_inLock(); } } catch (Exception e) { //出现异常,可以判断一下是否需要断开连接 if (e is SocketException) { SocketException es = (SocketException)e; if (es.SocketErrorCode == SocketError.Success || es.SocketErrorCode == SocketError.WouldBlock) { return; } } DoDisconnect(true, "EndSend Exception " + e.Message); } } } /// 修改发送消息的消息时序 private void UpdateMsgSendSequence() { //目前版本消息时序没有添加验证 } #endregion } }