1、C#Socket异步、同步通信服务端、客户端源码; 2、断线重连(服务端或客户端没有启动顺序要求,先开启的等待另一端连接);3、服务端支持同时连接多个客户端;4、阅读代码就明白通信道理,注释详细; 5、VS2015编译通过。
咱们直接进入正题,先看服务端代码。这个服务端用了异步处理,能同时接客多个客户端。注意看这个魔法方法BeginAccept,它像极了餐馆里的自动叫号机:
// 服务端核心代码(异步版) public class AsyncServer { private Socket _serverSocket; private List<Socket> _clientSockets = new List<Socket>(); // 客户池 public void Start(int port) { _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); _serverSocket.Bind(new IPEndPoint(IPAddress.Any, port)); _serverSocket.Listen(10); Console.WriteLine("服务端已启动,进入贤者模式..."); // 开始等待客人上门(非阻塞) _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null); } private void AcceptCallback(IAsyncResult ar) { Socket client = _serverSocket.EndAccept(ar); _clientSockets.Add(client); Console.WriteLine($"新客户上线,当前在线:{_clientSockets.Count}"); // 给新客户配专属服务员 byte[] buffer = new byte[1024]; client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), new ClientState { Socket = client, Buffer = buffer }); // 继续蹲点等新客 _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null); } }重点来了:BeginAccept是异步接客的关键,不会阻塞主线程。每个新连接进来都会触发AcceptCallback,这里用了递归式等待——处理完一个立即准备接待下一个。
客户端的重连机制像个倔强的追求者,核心代码如下:
// 客户端重连模块 public class ReconnectClient { private Socket _clientSocket; private Timer _reconnectTimer; public void Connect(string ip, int port) { _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 开启死亡循环模式尝试连接 _reconnectTimer = new Timer(state => { try { _clientSocket.Connect(ip, port); Console.WriteLine("成功勾搭上服务端!"); StartReceiving(); // 开始接收数据 _reconnectTimer.Dispose(); // 关掉定时器 } catch { Console.WriteLine("服务端不在线,5秒后继续撩..."); } }, null, 0, 5000); // 每5秒尝试一次 } }这个Timer相当于备胎定时器,每隔5秒就尝试连接,直到成功为止。注意finally里没有直接关闭socket,保持长连接状态。
再看数据接收的骚操作,用状态对象保存会话:
// 接收数据时的回调处理 private void ReceiveCallback(IAsyncResult ar) { ClientState state = (ClientState)ar.AsyncState; try { int bytesRead = state.Socket.EndReceive(ar); if (bytesRead > 0) { string msg = Encoding.UTF8.GetString(state.Buffer, 0, bytesRead); Console.WriteLine($"收到情报:{msg}"); // 继续监听下一波数据(像接龙游戏) state.Socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), state); } } catch (SocketException ex) { Console.WriteLine($"客户失联,错误码:{ex.SocketErrorCode}"); state.Socket.Close(); _clientSockets.Remove(state.Socket); // 从客户池踢出 } } // 会话状态封装类 public class ClientState { public Socket Socket { get; set; } public byte[] Buffer { get; set; } }这里用了ClientState对象来保存socket和buffer,避免闭包问题。异常处理中特别关注SocketException,能准确识别网络断开等状况。
1、C#Socket异步、同步通信服务端、客户端源码; 2、断线重连(服务端或客户端没有启动顺序要求,先开启的等待另一端连接);3、服务端支持同时连接多个客户端;4、阅读代码就明白通信道理,注释详细; 5、VS2015编译通过。
群发消息的实现像极了小区广播:
// 服务端广播功能 public void Broadcast(string message) { byte[] data = Encoding.UTF8.GetBytes(message); foreach (var client in _clientSockets.ToArray()) // ToArray防止遍历时集合被修改 { if (client.Connected) { client.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), client); } else { _clientSockets.Remove(client); // 清理僵尸连接 } } }这里用了ToArray来遍历副本,避免在迭代时修改集合导致的异常。BeginSend的异步发送不会阻塞服务端,适合高并发场景。
在VS2015中编译时要注意:项目属性→生成→目标框架要选.NET 4.5以上,确保Socket异步API可用。如果遇到SocketException 10054错误,那是客户端异常断线的正常反馈,咱们已经在接收回调里处理了。
最后来个心跳包检测存活的小技巧:
// 心跳检测 private void StartHeartbeat() { Timer heartbeatTimer = new Timer(state => { foreach (var client in _clientSockets.ToArray()) { if (!client.Poll(1000, SelectMode.SelectRead)) // 检测连接状态 { Console.WriteLine("检测到僵尸连接,执行清理"); client.Close(); _clientSockets.Remove(client); } } }, null, 60000, 60000); // 每分钟检测一次 }Poll方法能准确判断TCP连接的实际状态,比单纯判断Connected属性更可靠。这个定时器像扫地机器人,定期清理失效连接。
把这些模块组装起来,你就得到了一个支持异步通信、自动重连、多客户端管理的聊天服务器。代码已通过VS2015编译测试,直接拉取代码后记得修改IP和端口参数。完整源码在Github的SocketChatRoom项目中,注释详细到每个方法都有使用示例,保证你半小时内就能魔改成自己的通信框架。