Socket通信:如何维持连接并正确接收客户端数据?
Socket长连接通信问题修复
问题描述
尝试通过Socket实现服务端与客户端的长连接通信,需求如下:
- 维持两者的连接,持续监听客户端发送的数据
- 当客户端发送的数据包含"CLIENT[123]:"时,服务端回复输入内容;不符合条件则继续监听
但当前代码存在异常:启动服务端后,未收到客户端发送的数据却自动输出接收内容,且无法维持长连接。
原服务端代码
private static void server() { var localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.135"), Int32.Parse("8888")); // this socket listening connect from client var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listener.Bind(localEndPoint); listener.Listen(10); var size = 1024; var receiveBuffer = new byte[size]; while (true) { // this socket is receive/send data var socket = listener.Accept(); var length = socket.Receive(receiveBuffer); socket.Shutdown(SocketShutdown.Receive); var text = Encoding.ASCII.GetString(receiveBuffer, 0, length); Console.WriteLine($"Received from client: {text}"); if (text.Contains("CLIENT[123]:")) { Console.Write("#Send to client >>> "); var reply = Console.ReadLine(); var sendBuffer = Encoding.ASCII.GetBytes(reply); socket.Send(sendBuffer); socket.Shutdown(SocketShutdown.Send); socket.Close(); Array.Clear(receiveBuffer, 0, size); } } }
原客户端代码
private static void client() { var serverEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.135"), Int32.Parse("8888")); var size = 1024; var receiveBuffer = new byte[size]; while (true) { Console.Write("#Send to server >>> "); var text = Console.ReadLine(); var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); socket.Connect(serverEndpoint); var sendBuffer = Encoding.ASCII.GetBytes(text); socket.Send(sendBuffer); socket.Shutdown(SocketShutdown.Send); //get data from server var length = socket.Receive(receiveBuffer); var result = Encoding.ASCII.GetString(receiveBuffer, 0, length); Array.Clear(receiveBuffer, 0, size); socket.Shutdown(SocketShutdown.Receive); socket.Close(); } }
客户端测试数据示例
CLIENT[123]: Hi server, are you ok ?
问题原因
- 短连接逻辑错误:原服务端每次接受连接后,处理完一次数据就关闭socket,无法维持长连接;客户端每次发送数据都新建socket,用完即关,同样无法保持连接。
- 错误的Shutdown调用:服务端在
Receive()后立即调用Shutdown(SocketShutdown.Receive),直接关闭接收通道,导致后续无法监听客户端数据;客户端发送数据后关闭发送通道,服务端Receive()会返回0长度,此时空字符串被当成接收内容输出。 - 缓冲区清理不及时:服务端仅在符合条件时清理缓冲区,不符合条件时残留数据会干扰下一次接收。
修复方案
修复后的服务端代码
private static void server() { var localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.135"), 8888); var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listener.Bind(localEndPoint); listener.Listen(10); Console.WriteLine("服务端已启动,等待客户端连接..."); // 接受客户端连接,复用该socket维持长连接 Socket clientSocket = listener.Accept(); Console.WriteLine("客户端已连接"); var bufferSize = 1024; byte[] receiveBuffer = new byte[bufferSize]; while (true) { // 每次接收前清空缓冲区 Array.Clear(receiveBuffer, 0, bufferSize); int receiveLength = clientSocket.Receive(receiveBuffer); // 客户端断开连接时,Receive返回0,重新等待新连接 if (receiveLength == 0) { Console.WriteLine("客户端已断开连接,等待新连接..."); clientSocket.Close(); clientSocket = listener.Accept(); Console.WriteLine("新客户端已连接"); continue; } string receivedText = Encoding.ASCII.GetString(receiveBuffer, 0, receiveLength); Console.WriteLine($"Received from client: {receivedText}"); // 符合条件时回复客户端 if (receivedText.Contains("CLIENT[123]:")) { Console.Write("#Send to client >>> "); string replyText = Console.ReadLine(); byte[] sendBuffer = Encoding.ASCII.GetBytes(replyText); clientSocket.Send(sendBuffer); } } }
修复后的客户端代码
private static void client() { var serverEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.135"), 8888); Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { clientSocket.Connect(serverEndpoint); Console.WriteLine("已成功连接到服务端"); } catch (Exception ex) { Console.WriteLine($"连接服务端失败: {ex.Message}"); return; } var bufferSize = 1024; byte[] receiveBuffer = new byte[bufferSize]; while (true) { Console.Write("#Send to server >>> "); string sendText = Console.ReadLine(); // 输入exit可退出客户端 if (sendText.Equals("exit", StringComparison.OrdinalIgnoreCase)) { clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close(); break; } byte[] sendBuffer = Encoding.ASCII.GetBytes(sendText); clientSocket.Send(sendBuffer); // 接收服务端回复(仅符合条件时会有回复) int receiveLength = clientSocket.Receive(receiveBuffer); if (receiveLength > 0) { string replyText = Encoding.ASCII.GetString(receiveBuffer, 0, receiveLength); Console.WriteLine($"Received from server: {replyText}"); Array.Clear(receiveBuffer, 0, bufferSize); } } }
修复说明
- 长连接实现:服务端接受一次连接后,循环复用该socket进行通信;客户端仅创建一次socket,连接成功后持续使用。
- 断开处理:服务端检测到
Receive()返回0时,判定客户端断开,自动重新等待新连接。 - 缓冲区管理:每次接收前强制清空缓冲区,避免残留数据干扰。
- 移除无效Shutdown:仅在客户端退出时调用
Shutdown(SocketShutdown.Both)关闭通道,保留正常通信的通道权限。
内容的提问来源于stack exchange,提问作者Headshot
相关产品推荐
相关产品推荐

