c#检测tcp断开连接

我有两个简单的应用程序:

  • 等待特定tcp端口以供客户端连接的服务器应用程序。 然后倾听他的意见,发回一些反馈并断开该客户端的连接。

  • 表单应用程序连接到服务器应用程序,然后说出一些内容,然后等待反馈并断开与服务器的连接,然后在表单中显示反馈。

虽然服务器应用程序似乎行为正常(我已经使用Telnet对其进行了测试,并且我看到反馈并且我看到反馈后直接发生了断开连接),但是表单应用程序似乎并没有注意到与服务器的断开连接 。 (即使在服务器断开连接后,TcpClient.Connected仍然保持为真)

我的问题是:为什么TcpClient.Connected保持正确,我怎么知道服务器是否/何时断开连接?

这是我的完整代码:

表格申请:

using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Windows.Forms; using System.Threading; namespace Sender { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void sendButton_Click(object sender, EventArgs e) { TcpClient tcpClient = new TcpClient(); tcpClient.Connect(IPAddress.Parse("127.0.0.1"), 81); responseLabel.Text = "waiting for response..."; responseLabel.Invalidate(); // write request NetworkStream networkStream = tcpClient.GetStream(); byte[] buffer = (new ASCIIEncoding()).GetBytes("Hello World! "); networkStream.Write(buffer, 0, buffer.Length); networkStream.Flush(); // read response Thread readThread = new Thread(new ParameterizedThreadStart(ReadResponse)); readThread.Start(tcpClient); } void ReadResponse(object arg) { TcpClient tcpClient = (TcpClient)arg; StringBuilder stringBuilder = new StringBuilder(); NetworkStream networkStream = tcpClient.GetStream(); bool timeout = false; DateTime lastActivity = DateTime.Now; while (tcpClient.Connected && !timeout) { if (networkStream.DataAvailable) { lastActivity = DateTime.Now; while (networkStream.DataAvailable) { byte[] incomingBuffer = new byte[1024]; networkStream.Read(incomingBuffer, 0, 1024); char[] receivedChars = new char[1024]; (new ASCIIEncoding()).GetDecoder().GetChars(incomingBuffer, 0, 1024, receivedChars, 0); stringBuilder.Append(receivedChars); } } else { if (DateTime.Now > lastActivity.AddSeconds(60)) timeout = true; } System.Threading.Thread.Sleep(50); } Invoke((MethodInvoker)delegate { responseLabel.Text = "Response from Listener:\n" + stringBuilder.ToString(); responseLabel.Invalidate(); }); if (timeout) { Console.Write("A timeout occured\n"); networkStream.Close(); tcpClient.Close(); } } } } 

服务器应用:

 using System.Net; using System.Net.Sockets; using System.Text; using System; using System.Threading; namespace Listener { class Program { static void Main(string[] args) { var tcpListener = new TcpListener(IPAddress.Any, 81); tcpListener.Start(); Thread clientThread = new Thread(new ParameterizedThreadStart(Listen)); clientThread.Start(tcpListener); } static void Listen(object arg) { TcpListener tcpListener = (TcpListener)arg; while (true) { TcpClient tcpClient = tcpListener.AcceptTcpClient(); Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClient)); clientThread.Start(tcpClient); } } static void HandleClient(object arg) { TcpClient tcpClient = (TcpClient)arg; StringBuilder stringBuilder = new StringBuilder(); ASCIIEncoding encoder = new ASCIIEncoding(); DateTime lastActivity = DateTime.Now; // read request NetworkStream networkStream = tcpClient.GetStream(); int timeout = 5; // gives client some time to send data after connecting while (DateTime.Now < lastActivity.AddSeconds(timeout) && stringBuilder.Length==0) { if (!networkStream.DataAvailable) { System.Threading.Thread.Sleep(50); } else { while (networkStream.DataAvailable) { lastActivity = DateTime.Now; byte[] incomingBuffer = new byte[1024]; networkStream.Read(incomingBuffer, 0, 1024); char[] receivedChars = new char[1024]; encoder.GetDecoder().GetChars(incomingBuffer, 0, 1024, receivedChars, 0); stringBuilder.Append(receivedChars); } } } string request = stringBuilder.ToString(); // write response string response = "The listener just received: " + request; byte[] outgoingBuffer = encoder.GetBytes(response); networkStream.Write(outgoingBuffer, 0, outgoingBuffer.Length); networkStream.Flush(); networkStream.Close(); tcpClient.Close(); } } } 

连接关闭时,TcpClient / NetworkStream不会收到通知。 您可以使用的唯一选项是在写入流时捕获exception。

几年前,我们开始使用套接字而不是tcp客户端。 与tcpclient相比,socket更有用。

您可以使用几种方法

民意调查就是其中之一

http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.poll.aspx

您还可以检查Write本身的结果。 它为您提供实际写入的字节数。

Connected属性本身仅反映上次操作的状态。 其文档说明“Connected属性的值反映了最近一次操作时的连接状态。如果需要确定连接的当前状态,请进行非阻塞,零字节发送调用。如果调用成功返回或抛出WAEWOULDBLOCK错误代码(10035),然后套接字仍然连接;否则,套接字不再连接。“

http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.connected.aspx

 networkStream.DataAvailable 

如果套接字在服务器端关闭,则此属性不会通知您。

在您的情况下,您可以实现“keepalive”function,每隔t分钟/秒轮询一次连接,或者在尝试从套接字读取或写入时添加大量的try / catches。 当我使用TCP时,我只包含一个进入每个catch语句的Reconnect()方法。