如何通过Socket/TcpClient维持与服务器的ESTABLISHED连接?
TCP连接维持问题排查与疑问
我已成功与服务器建立连接,通过CMD命令netstat -a -n可查看连接状态,但约21秒后连接会从ESTABLISHED变为CLOSE_WAIT,希望始终维持ESTABLISHED状态。
我先后尝试了两种C#实现方案:
方案1:直接使用Socket
设置KeepAlive后,连接仍会转为CLOSE_WAIT且无异常提示,代码如下:
private void _connect() { var IpEndPoint = new IPEndPoint(IPAddress.Parse("10.10.10.120"), 3000); var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); client.SendTimeout = 60; client.ReceiveTimeout = 60; try { client.Connect(IpEndPoint); int byteCount = 0; byte[] bytes = new byte[256]; while (true) { byteCount = client.Receive(bytes); if (byteCount == 0) // 未从服务器接收数据时,客户端发送 dummy 数据 { byte[] data_send = Encoding.ASCII.GetBytes("Hi, dummy data"); client.Send(data_send); } else // 接收到服务器数据时,写入日志文件 { byte[] byte_rec = new byte[byteCount]; Buffer.BlockCopy(bytes, 0, byte_rec, 0, byteCount); txt_log.Text = Encoding.ASCII.GetString(byte_rec); } } } catch (Exception ex) { MessageBox.Show(ex.Message); } }
方案2:使用TcpClient
连接约20秒后在netstat中无状态显示,出现**"Unable to read data from the transport connection: An established connection was aborted by the software in your host machine"**异常,代码如下:
private void _connect() { TcpClient client1 = new TcpClient(); try { client1.Connect("10.10.10.120", 3000); NetworkStream stream1 = client1.GetStream(); var bytes = new byte[256]; while (true) { int numbyte = stream1.Read(bytes, 0, bytes.Length); if (numbyte == 0) { byte[] data_send = Encoding.ASCII.GetBytes("Hi, dummy data"); stream1.Write(data_send, 0, data_send.Length); } else { byte[] byte_rec = new byte[numbyte]; Buffer.BlockCopy(bytes, 0, byte_rec, 0, numbyte); txt_log.Text = Encoding.ASCII.GetString(byte_rec); } } } catch (Exception ex) { MessageBox.Show(ex.Message); } }
优化后情况及疑问
后续优化代码后,无断点运行时可维持连接超10分钟,但调试时发现NetworkStream的DataAvailable首次为true,之后始终为false,添加断点会导致连接断开并抛出上述异常。想了解DataAvailable状态变化的原因及如何彻底解决连接维持问题。优化后的代码如下:
private async void _connect() { var serverEndpoint = new IPEndPoint(IPAddress.Parse(_ip), _port); client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); client.Connect(serverEndpoint); client.NoDelay = true; client.SendTimeout = 60000; client.ReceiveTimeout = 60000; byte[] myReadBuffer = new byte[1024]; int numberOfBytesRead = 0; bool _flag = false; while (true) { stream = new NetworkStream(client); // 基于Socket创建流 if (stream.CanRead) { do { if (_flag) { numberOfBytesRead = 0; goto receiveskip; } if (numberOfBytesRead == 0) // 先向服务器发送dummy数据 { byte[] data_dummy = Encoding.ASCII.GetBytes("dummy_abc"); stream.Write(data_dummy, 0, data_dummy.Length); stream.Flush(); } numberOfBytesRead = stream.Read(myReadBuffer, 0, myReadBuffer.Length); byte[] bytes_rec = new byte[numberOfBytesRead]; Buffer.BlockCopy(myReadBuffer, 0, bytes_rec, 0, numberOfBytesRead); // 首次发送dummy_abc后接收服务器数据 if(bytes_rec.Length == 14) { txt_log.Text += Encoding.ASCII.GetString(bytes_rec); // 写入文本框 } // 后续接收服务器数据(长度大于14) if (bytes_rec.Length > 14) { byte[] data_rep = Encoding.ASCII.GetBytes("Ok, thank server"); // 客户端回复服务器 stream.Write(data_rep, 0, data_rep.Length); stream.Flush(); _flag = true; continue; } receiveskip:; } while (stream.DataAvailable); } else { MessageBox.Show("Cannot read from this NetworkStream."); } } } catch (Exception ex) { stream.Close(); client.Close(); MessageBox.Show(ex.Message); } }
内容的提问来源于stack exchange,提问作者Headshot
相关产品推荐
相关产品推荐

