记录下这两天修改后的Socket客户端类,用在unity上的。
服务器返回的消息采用 4+n 简单协议,即数据包的前4个字节代表真实数据长度.
- 因为需求会切换服务器地址,所以支持切换服务器重新创建连接;
- 创建一个新连接后,会立刻创建一个线程用于监听服务器返回数据;
- 创建一个定时处理线程,当连接闲置15秒后,关闭当前线程;
代码很简单,只有核心代码,稍微修改下可以直接使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
| static DateTime lastAvtiveDateTime = DateTime.Now; static Socket tcpClient; static Thread tcpClientThread; static bool tcpRecvThreadRuning; static IPEndPoint CurrentRemoteEP; static bool tcpIsWorking = false; const int tcpCacheSeconds = 15;
public static void SendTcp(byte[] buffer, IPEndPoint remoteEP) { lastAvtiveDateTime = DateTime.Now; if (tcpClient == null) { InitTcpClient(); }
if (tcpClientThread == null) { tcpClientThread = new Thread(new ThreadStart(CloseTcpWork)); tcpClientThread.IsBackground = true; tcpClientThread.Start(); }
if (!tcpClient.Connected || remoteEP.ToString() != CurrentRemoteEP.ToString()) { CloseTcpClient(); CurrentRemoteEP = remoteEP;
if (ConnectTo(CurrentRemoteEP)) { Debug.Log("###通讯报告###:连接服务器成功!"); CreateRecvThread(); } else { OnError(new Exception("###通讯报告###:创建服务器连接失败!")); return; } } tcpIsWorking = true; try { tcpClient.Send(buffer); Debug.Log("###通讯报告###:数据发送成功!"); } catch (Exception ex) { CloseTcpClient(); tcpIsWorking = false; OnError(new Exception("###通讯报告###:数据发送失败!", ex)); } finally { lastAvtiveDateTime = DateTime.Now; } }
private static void InitTcpClient() { tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); }
private static bool ConnectTo(IPEndPoint remoteEP) { try { tcpClient.Connect(remoteEP); return true; } catch { tcpClient.Close(); tcpClient = null; return false; } }
private static void CreateRecvThread() { Thread tcpRecvThread = new Thread(new ThreadStart(Recv)); tcpRecvThread.IsBackground = true; tcpRecvThreadRuning = true; tcpRecvThread.Start(); }
private static void Recv() { Debug.Log("###通讯报告###:数据接收线程已启动!"); while (tcpRecvThreadRuning) { if (tcpIsWorking) { try { byte[] recv_length = new byte[4];
int length = tcpClient.Receive(recv_length); if (length < 0) { throw new Exception("###通讯报告###:连接出错!"); } else if (length == 0) { throw new Exception("###通讯报告###:连接已从远程关闭!"); } else if (length == 4) { int packageLen = BitConverter.ToInt32(recv_length, 0); byte[] recv_data = new byte[packageLen]; int recvDataLength; using (MemoryStream stream = new MemoryStream()) { do { recvDataLength = tcpClient.Receive(recv_data); if (recvDataLength > 0) { stream.Write(recv_data, 0, recvDataLength); } } while (stream.Length < packageLen);
Debug.Log("###通讯报告###:接收数据长度 " + stream.Length); if (packageLen == stream.Length) { lastAvtiveDateTime = DateTime.Now; tcpIsWorking = false; OnNewPackageReceived(stream.ToArray()); continue; } } } throw new Exception("###通讯报告###:接收数据长度不正确!"); } catch (Exception ex) { tcpClient.Close(); tcpClient = null; Debug.Log(ex.Message); tcpIsWorking = false; OnError(ex); break; } } else { Thread.Sleep(0); } } Debug.Log("###通讯报告###:数据接收线程已关闭!"); }
private static void CloseTcpClient() { tcpRecvThreadRuning = false; if (tcpClient.Connected) { tcpClient.Close(); tcpClient.Dispose(); Debug.Log("###通讯报告###:服务器连接已关闭!"); } InitTcpClient(); }
private static void CloseTcpWork() { while (true) { if (!tcpIsWorking && DateTime.Now.AddSeconds(-tcpCacheSeconds) > lastAvtiveDateTime) { CloseTcpClient(); } if (!tcpClient.Connected) { Thread.Sleep(tcpCacheSeconds * 1000); } else { Thread.Sleep(1000); }
} }
private static void OnError(Exception e) { Debug.Log(e.Message); }
private static void OnNewPackageReceived(byte[] bytes) { Debug.Log("###通讯报告###:数据接收成功!"); }
|
记录一篇介绍socket的文章:你得学会并且学得会的Socket编程基础知识