0.基于上一篇的c#之Socket(同步)通信,在几个大神评论之后,发明是有挺多处所不敷的,所以写了一个改造版本的基于c#的异步Socket通信。再加深一下对Socket的使用和理解。此中客户端和处事端均给与WPF界面,实现了心跳,断线重连,一个处事端对应多个客户真个成果。
一.处事端
1.1 先创建一个Socket实例,并绑定到20000端标语;通过Listen要领开始监听并设置最大监听数量。
//新建一个Socket处事端实例,并绑定到20000端口 this.socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); this.socketServer.Bind(new IPEndPoint(IPAddress.Any, 20000)); //设置最大监听数量 this.socketServer.Listen(10);
1.2 开始异步监听客户端,使用的是BeginAccept与EndAccept,当有客户端连接后会自动挪用回调函数,此时开始心跳并将客户真个Socket与心跳等信息插手到全局字典中去。
this.socketServer.BeginAccept(ar => { Socket _socket = socketServer.EndAccept(ar); //开始心跳 System.Timers.Timer heartbeatTimer = new System.Timers.Timer(); heartbeatTimer.Interval = 600000; heartbeatTimer.Elapsed += new System.Timers.ElapsedEventHandler((s, e) => heartbeatTimerIsUp(s, e, _socket)); heartbeatTimer.Start(); SocketInfo info = new SocketInfo(); info.heartbeatTimer = heartbeatTimer; this.socketInfoDic.Add(_socket, info); //开始接收数据 thdRevMethod(_socket); //开始下一次监听 ListenSocket(); }, null);
1.3 接收数据,当上一步中有客户端连接告成后,即可开启异步接收来自客户真个数据;使用的是BeginReceive与EndReceive,当接收到来自客户真个数据后,会自动挪用回调函数。由于接收到的数据的巨细不确定,所以这里每次接收1024字节,然后将接收到的数据拼接起来,用到Available 属性,为可读取的字节数,如果小于即是0,说明这次数据接收完毕。
Socket _socket = obj as Socket; if (this.socketInfoDic.ContainsKey(_socket)) { SocketInfo socketInfo = socketInfoDic[_socket]; //开始接收动静 _socket.BeginReceive(socketInfo.tempByte, 0, socketInfo.tempByte.Length, SocketFlags.None, ar => { try { int resInt = _socket.EndReceive(ar); socketInfo.contentByte = socketInfo.contentByte.Concat(socketInfo.tempByte).ToArray(); socketInfo.tempByte = new byte[1024]; if (_socket.Available <= 0) { int actualLength = socketInfo.contentByte.Length - (socketInfo.tempByte.Length - resInt); string res = Encoding.Default.GetString(socketInfo.contentByte, 0, actualLength); socketInfo.contentByte = new byte[0]; } thdRevMethod(_socket); } catch (SocketException sex) { if (sex.SocketErrorCode == SocketError.ConnectionReset) { //当客户端断开连接,从列表中移除该客户端 if (this.socketInfoDic.ContainsKey(_socket)) { this.socketInfoDic.Remove(_socket); } } } catch (Exception ex) { MessageBox.Show("措施呈现异常:" + ex); } }, null); }
1.4 发送数据,用到的是BeginSend与EndSend,发送告成后会自动挪用回调函数,此中EndSend()要领返回告成发送的字节数量
byte[] byteStr = Encoding.Default.GetBytes(msg); _socket.BeginSend(byteStr, 0, byteStr.Length, SocketFlags.None, ar => { _socket.EndSend(ar); }, null);
二.客户端
2.1 新建Socket实例并开始异步连接随处事端,用到的是BeginConnect与EndConnect,连接告成会自动挪用回调函数,此时可开始心跳,接收发送数据。
// 新建客户端实例,并连接随处事端地址的端标语 this.socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //连接随处事端 this.socketClient.BeginConnect("127.0.0.1", 20000, ar => { try { this.socketClient.EndConnect(ar); this.thdRevMethod(); } catch (SocketException sex) { if (sex.SocketErrorCode == SocketError.ConnectionRefused) { this.reconnectTimer.Start(); this.heartbeatTimer.Stop(); } } catch (Exception) { this.heartbeatTimer.Stop(); throw; } }, null);
2.2 发送与接收数据(与客户端类似)
三.运行示例
四.总结
假如上述描述,或者代码逻辑中有任何问题,但愿列位大神资助指出来,感谢!
此中需要注意的处所如下: