C#检测TCP断开(c# detecting tcp disconnect)

2019-07-20 11:53发布

我有两个简单的应用:

  • 一个特定的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();
        }
    }

}

Answer 1:

的TcpClient /的NetworkStream当连接关闭时无法得到通知。 提供给您唯一的选择就是写入流时捕获异常。

几年前我们搬到了使用套接字而不是TCP客户端。 插座是相比于TcpClient的更可用。

有一对夫妇,你可以使用方法

民意调查是其中之一

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

你也可以做自己写出来的结果进行检查。 它可以让你实际写入的字节数。

connected属性本身只反映了最后一次操作的状态。 它的文件指出“Connected属性的值反映了连接的最近操作的状态。如果您需要确定连接的当前状态,使非阻塞,零字节发送呼叫。如果呼叫成功返回或引发WAEWOULDBLOCK的错误代码(10035),则插座仍然连接;否则,插座不再连接“。

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



Answer 2:

networkStream.DataAvailable

如果套接字服务器端关闭这个属性不会通知您。

在您的情况,您可以实现在您轮询连接每隔t分/秒,或添加大量的try /捕捞的,只要你尝试读取或从插座上写了一个“保活”的功能。 当我使用TCP,我只是包括进入每一个catch语句重新连接()方法。



文章来源: c# detecting tcp disconnect