NetSocket.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System;
  5. using System.Net;
  6. using System.Net.Sockets;
  7. using System.Text;
  8. using System.IO;
  9. namespace Engine.Net
  10. {
  11. /// <summary>服务器类型</summary>
  12. public enum ESockeType
  13. {
  14. /// <summary>游戏服务器</summary>
  15. Game = 0,
  16. }
  17. /// <summary>服务器类型</summary>
  18. public enum ESocketConnectType
  19. {
  20. /// <summary>连接类型</summary>
  21. TCP = 0,
  22. UDP = 1,
  23. }
  24. /// <summary>客户端socket对象</summary>
  25. public class NetSocket
  26. {
  27. /// <summary>连接对象</summary>
  28. public Socket mSocket = null;
  29. /// <summary>接收数据的位置。</summary>
  30. private int nRecvPos = 0;
  31. /// <summary>保存接受到的数据</summary>
  32. private byte[] arrRecvBuff;
  33. /// <summary>接受到的消息</summary>
  34. private Queue<NetMsg> mQueueRecvMsg;
  35. /// <summary>消息日志对象</summary>
  36. public NetMsgLog netMsgLog = new NetMsgLog();
  37. /// <summary>对发送的优化,增加处理:多线程调用SendMsg时的处理,BeginSend和EndSend的串行处理,增加发送缓冲区</summary>
  38. private System.Object mSendLock = new System.Object();
  39. /// <summary>需要发送的内容</summary>
  40. private byte[] mSendBuff;
  41. /// <summary>发送的长度</summary>
  42. private int nSendBuffDataLen;
  43. /// <summary>表示已经调用了BeginSend,正在等待结束</summary>
  44. private bool bSendPending = false;
  45. /// <summary>服务器类型</summary>
  46. //public ESockeType socketType = ESockeType.Game;
  47. /// <summary>连接类型</summary>
  48. public ESocketConnectType socketConnectType = ESocketConnectType.TCP;
  49. /// <summary>构造函数</summary>
  50. public NetSocket(ESockeType type, ESocketConnectType connectType)
  51. {
  52. //socketType = type;
  53. socketConnectType = connectType;
  54. arrRecvBuff = new byte[NetMsg.MAX_MSG_LEN];
  55. nRecvPos = 0;
  56. mQueueRecvMsg = new Queue<NetMsg>();
  57. mSendBuff = new byte[NetMsg.MAX_MSG_LEN];
  58. nSendBuffDataLen = 0;
  59. }
  60. #region 创建和断开连接
  61. /// <summary>创建Socket连接</summary>
  62. public bool Connect(string strIp, int nPort)
  63. {
  64. //如果存在连接线断开
  65. if (mSocket != null)
  66. {
  67. DoDisconnect(false);
  68. }
  69. try
  70. {
  71. if(socketConnectType == ESocketConnectType.TCP)
  72. {
  73. mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  74. }
  75. else if(socketConnectType == ESocketConnectType.UDP)
  76. {
  77. mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  78. }
  79. CDebug.Log("Connect " + strIp + " "+nPort);
  80. mSocket.BeginConnect(strIp, nPort, new AsyncCallback(ConnectCallback), mSocket);
  81. //Debug.Log(mSocket.ReceiveBufferSize + " " + mSocket.SendBufferSize);
  82. mSocket.ReceiveBufferSize = 204800;
  83. mSocket.SendBufferSize = 204800;
  84. //Debug.Log(mSocket.ReceiveBufferSize + " " + mSocket.SendBufferSize);
  85. }
  86. catch (SocketException e)
  87. {
  88. SendDisconnectMsg(true);
  89. CDebug.LogError(e.Message);
  90. return false;
  91. }
  92. return true;
  93. }
  94. /// <summary>Socket连接完成</summary>
  95. private void ConnectCallback(IAsyncResult ar)
  96. {
  97. try
  98. {
  99. Socket client = (Socket)ar.AsyncState;
  100. client.EndConnect(ar);
  101. nRecvPos = 0;
  102. if (!StartRecvMsg())
  103. {
  104. DoDisconnect();
  105. }
  106. SendConnectGSuccess();
  107. }
  108. catch (SocketException e)
  109. {
  110. CDebug.LogError(e.Message);
  111. mSocket.Close();
  112. mSocket = null;
  113. }
  114. }
  115. /// <summary>Socket对象是否连接中</summary>
  116. public bool IsConnected()
  117. {
  118. return (mSocket == null) ? false : mSocket.Connected;
  119. }
  120. /// <summary>发送Socket连接失败的消息</summary>
  121. private void SendDisconnectMsg(bool bReceiveDisconnMsg = true)
  122. {
  123. if (bReceiveDisconnMsg == true)
  124. {
  125. NetMsg msg = new NetMsg(NetCode.MSG_CONE_CONNECT_FAIL);
  126. //msg.arrData.WriteInt((int)socketType);
  127. mQueueRecvMsg.Enqueue(msg);
  128. }
  129. }
  130. /// <summary>服务器连接成功</summary>
  131. private void SendConnectGSuccess()
  132. {
  133. NetMsg msg = new NetMsg(NetCode.MSG_CONE_CONNECT_SUCCESS);
  134. //msg.arrData.WriteInt((int)socketType); ;
  135. mQueueRecvMsg.Enqueue(msg);
  136. }
  137. #endregion
  138. #region 接受消息相关
  139. /// <summary>获得一个已经接受到的消息</summary>
  140. public NetMsg RecvMsg()
  141. {
  142. if (mQueueRecvMsg.Count == 0)
  143. return null;
  144. NetMsg msg = null;
  145. try
  146. {
  147. msg = mQueueRecvMsg.Dequeue();
  148. }
  149. catch
  150. { }
  151. return msg;
  152. }
  153. /// <summary>开始接受消息</summary>
  154. private bool StartRecvMsg()
  155. {
  156. if (mSocket == null)
  157. return false;
  158. try
  159. {
  160. SocketError err;
  161. mSocket.BeginReceive(arrRecvBuff, nRecvPos, arrRecvBuff.Length - nRecvPos, SocketFlags.None, out err, new AsyncCallback(RecvCallback), this);
  162. }
  163. catch
  164. {
  165. return false;
  166. }
  167. return true;
  168. }
  169. /// <summary>消息接受完成</summary>
  170. private void RecvCallback(IAsyncResult ar)
  171. {
  172. int nRecv = 0;
  173. try
  174. {
  175. if (mSocket != null)
  176. {
  177. SocketError err;
  178. nRecv = mSocket.EndReceive(ar, out err);
  179. }
  180. else
  181. {
  182. SendDisconnectMsg();
  183. return;
  184. }
  185. }
  186. catch (System.Exception e)
  187. {
  188. //出现异常
  189. #if UNITY_EDITOR
  190. CDebug.LogError("recv msg error "+ e.Message + e.StackTrace);
  191. #endif
  192. SendDisconnectMsg();
  193. return;
  194. }
  195. //如果接受的字节数是0,断开连接
  196. if (nRecv == 0)
  197. {
  198. DoDisconnect(true, "Common disconnect");
  199. return;
  200. }
  201. //CDebug.Log("字节长度 " + nRecv);
  202. //追加接受的到字节
  203. nRecvPos += nRecv;
  204. //循环读取接受到的全部消息内容
  205. do
  206. {
  207. if (!IsConnected())
  208. break;
  209. NetMsg msg = null;
  210. if (ParseMsg(ref arrRecvBuff, ref nRecvPos, ref msg))
  211. {
  212. //添加接收时序
  213. UpdateMsgResSequence();
  214. //解析成功吧消息添加到队列中
  215. mQueueRecvMsg.Enqueue(msg);
  216. //接受消息日志
  217. netMsgLog.ResMessage(msg);
  218. }
  219. else
  220. {
  221. //解析失败
  222. break;
  223. }
  224. } while (true);
  225. //继续挂起接收消息
  226. StartRecvMsg();
  227. }
  228. /// <summary>解析消息</summary>
  229. private bool ParseMsg(ref byte[] buff, ref int nLen, ref NetMsg msg)
  230. {
  231. //当前数据长度小于固定长度,返回失败
  232. if (nLen < NetMsg.MIN_MSG_LEN)
  233. return false;
  234. msg = NetMsg.OnCreateNetMsg(buff);
  235. //获得当前消息的长度
  236. int nMsgSize = msg.arrData.ReadInt();
  237. //判断消息长度是否合法
  238. if (nMsgSize < NetBytes.INT32_LEN || nMsgSize > NetMsg.MAX_MSG_LEN)
  239. {
  240. //消息长度非法,断开连接
  241. DoDisconnect(true, "Invalid msg len " + nMsgSize);
  242. return false;
  243. }
  244. //如果当前消息不完整,失败
  245. if (nLen < nMsgSize)
  246. {
  247. CDebug.Log("如果当前消息不完整 " + nLen + " " + nMsgSize);
  248. return false;
  249. }
  250. if (!msg.ReadMessage(buff, nMsgSize))
  251. {
  252. RemoveBuff(ref buff, ref nLen, nMsgSize);
  253. CDebug.Log("读取失败 " + nLen + " " + nMsgSize);
  254. return false;
  255. }
  256. //清除该消息的缓冲区
  257. RemoveBuff(ref buff, ref nLen, nMsgSize);
  258. return true;
  259. }
  260. /// <summary>清理消息buff</summary>
  261. private void RemoveBuff(ref byte[] buff, ref int nLen, int nSize)
  262. {
  263. if (nSize <= nLen)
  264. {
  265. int nCopyLen = nLen - nSize;
  266. for (int i = 0; i < nCopyLen; ++i)
  267. {
  268. buff[i] = buff[i + nSize];
  269. }
  270. nLen -= nSize;
  271. }
  272. }
  273. /// <summary>断开连接</summary>
  274. public void DoDisconnect(bool bReceiveDisconnMsg = true, string strReason = null)
  275. {
  276. if (!IsConnected())
  277. {
  278. return;
  279. }
  280. if (!string.IsNullOrEmpty(strReason))
  281. {
  282. CDebug.LogError("Disconnect connection: " + strReason);
  283. }
  284. if (mSocket != null)
  285. {
  286. SendDisconnectMsg(bReceiveDisconnMsg);
  287. CDebug.Log("尝试断开socket链接" + mSocket.Connected);
  288. try
  289. {
  290. mSocket.Disconnect(true);
  291. mSocket.Close();
  292. }
  293. catch
  294. {
  295. CDebug.LogError("DisConnected");
  296. }
  297. mSocket = null;
  298. nRecvPos = 0;
  299. }
  300. }
  301. /// <summary>修改接受消息的消息时序</summary>
  302. private void UpdateMsgResSequence()
  303. {
  304. //目前版本消息时序没有添加验证
  305. }
  306. #endregion
  307. #region 发送消息相关
  308. /// <summary>发送消息</summary>
  309. public bool SendMsg(NetMsg msg)
  310. {
  311. if (mSocket == null)
  312. return false;
  313. lock (mSendLock)
  314. {
  315. byte[] buff = null;
  316. buff = msg.FastPackMsg();
  317. if (buff == null)
  318. return false;
  319. //修改发送消息的消息时序
  320. UpdateMsgSendSequence();
  321. int nNewSendBuffDataLen = nSendBuffDataLen + buff.Length;
  322. if (mSendBuff.Length < nNewSendBuffDataLen)
  323. {
  324. System.Array.Resize<byte>(ref mSendBuff, nNewSendBuffDataLen * 2);
  325. }
  326. System.Array.Copy(buff, 0, mSendBuff, nSendBuffDataLen, buff.Length);
  327. nSendBuffDataLen += buff.Length;
  328. //发送日志
  329. netMsgLog.SendMessage(msg);
  330. SendDataInBuffer_inLock();
  331. }
  332. return true;
  333. }
  334. /// <summary>发送消息</summary>
  335. private void SendDataInBuffer_inLock()
  336. {
  337. if (bSendPending)
  338. return;
  339. try
  340. {
  341. if (nSendBuffDataLen == 0)
  342. return;
  343. SocketError err;
  344. mSocket.BeginSend(mSendBuff, 0, nSendBuffDataLen, SocketFlags.None, out err, SendCallback, this);
  345. if (err != SocketError.Success && err != SocketError.WouldBlock)
  346. {
  347. DoDisconnect(true, "BeginSend error " + err.ToString());
  348. return;
  349. }
  350. bSendPending = true;
  351. }
  352. catch (Exception e)
  353. {
  354. if (e is SocketException)
  355. {
  356. SocketException es = (SocketException)e;
  357. if (es.SocketErrorCode == SocketError.Success
  358. || es.SocketErrorCode == SocketError.WouldBlock)
  359. {
  360. return;
  361. }
  362. }
  363. DoDisconnect(true, "BeginSend excption: " + e.Message);
  364. return;
  365. }
  366. }
  367. /// <summary>发送消息完成</summary>
  368. private void SendCallback(IAsyncResult ar)
  369. {
  370. lock (mSendLock)
  371. {
  372. bSendPending = false;
  373. if (mSocket == null)
  374. return;
  375. try
  376. {
  377. SocketError err;
  378. int nSendLen = mSocket.EndSend(ar, out err);
  379. if (nSendLen <= 0)
  380. {
  381. if (err != SocketError.Success && err != SocketError.WouldBlock)
  382. {
  383. DoDisconnect(true, "EndSend error " + err.ToString());
  384. }
  385. return;
  386. }
  387. RemoveBuff(ref mSendBuff, ref nSendBuffDataLen, nSendLen);
  388. if (nSendBuffDataLen > 0)
  389. {
  390. SendDataInBuffer_inLock();
  391. }
  392. }
  393. catch (Exception e)
  394. {
  395. //出现异常,可以判断一下是否需要断开连接
  396. if (e is SocketException)
  397. {
  398. SocketException es = (SocketException)e;
  399. if (es.SocketErrorCode == SocketError.Success
  400. || es.SocketErrorCode == SocketError.WouldBlock)
  401. {
  402. return;
  403. }
  404. }
  405. DoDisconnect(true, "EndSend Exception " + e.Message);
  406. }
  407. }
  408. }
  409. /// <summary>修改发送消息的消息时序</summary>
  410. private void UpdateMsgSendSequence()
  411. {
  412. //目前版本消息时序没有添加验证
  413. }
  414. #endregion
  415. }
  416. }