如何在断开连接后重用或重新连接到同一端口上的套接字?

本文关键字:套接字 重新连接 断开 连接 | 更新日期: 2023-09-27 18:14:34

我正在做一个简单的项目,涉及单个服务器程序和单个客户程序。它需要检查客户端是否连接(从服务器端),反之亦然。

当客户端失去网络连接时,服务器需要知道它已断开连接。然后,客户端需要重新连接到服务器,当它重新获得互联网

当客户端失去互联网,然后重新获得互联网,我不能使用相同的端口重新连接。

我试着离开服务器监听,而不是关闭套接字,这也不起作用。我已经尝试了很多属性的套接字在重用方面,我也尝试了挥之不去的东西了。

我看到它可以在注册表中被操作系统设置的一些TIME_WAIT属性卡住(在Windows的情况下)。我的问题,重申一下,是能够使用相同的套接字(更重要的是相同的端口)重新连接后,客户端丢失和恢复互联网,并仍在收听等待重新连接。

就像我说的,我可以检测它何时从服务器端断开连接,也在客户端上,但当我尝试使用相同的端口和相同的套接字或重新启动的套接字重新连接时,它仍然不会连接,它根本不会出现。有什么建议可以帮助解决这个问题吗?为了解决这个问题我已经研究了很长时间。

场景:

  1. 服务器正在监听
  2. 客户端连接到服务器
  3. 断开客户端连接
  4. 将客户端网线插入
  5. 客户端自动重新连接到服务器(目前没有在同一端口上这样做)

TL;DR在客户端-服务器模式下丢失和恢复互联网,但不能使用相同的套接字和端口连接到服务器。

<标题>代码:
    private void button2_Click(object sender, EventArgs e)
    {
        // This will stop the threads/connections and toggle the button back to its original state
        if (button2.Text == "Stop Listening")
        {
            listener.Close();
            stop = true;
            threadsActive = false;
            button2.Text = "Start Listening";
            textBox1.AppendText("Manually Closed Threads/Connections" + Environment.NewLine);
        }
        else
        {
            listenThread = new Thread(listenLoop);
            listenThread.IsBackground = true;
            status = new Thread(checkIfOnline);
            status.IsBackground = true;
            stop = false;
            threadsActive = true;
            button2.Text = "Stop Listening";
            localEndPoint = new IPEndPoint(IPAddress.Parse("129.59.79.65"), 3000);
            listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            listenThread.Start();
            status.Start();
        }
    }

====================================================

private void listenLoop()
    {
        try
        {
            listener.Bind(localEndPoint);
            listener.Listen(100);
            textBox1.AppendText("Waiting for a client..." + Environment.NewLine);
            listener = listener.Accept();
            textBox1.AppendText("Client Connected!!" + Environment.NewLine);
            status.Start();
            while (!close)
            {
                if (stop)
                    return;
                // server connection loop
            }
            if(close)
                return;
        }
        catch (Exception excp)
        {

        }
    }

====================================================

private void ResetSocket()
    {
        // stop all threads and connections
        stop = true;
        listener.Close();
        textBox1.AppendText("Attempting to kill threads..." + Environment.NewLine);
        //while (listenThread.IsAlive == true || status.IsAlive == true) { /*loop until the threads are killed*/ textBox1.AppendText("Closing Threads..."); }
        //listener.Close();
        threadsActive = false;
        textBox1.AppendText("All Threads/Connections Closed" + Environment.NewLine + "Restarting Threads/Connections..." + Environment.NewLine);
        // re-establish and start threads and connections again
        stop = false;
        listenThread = new Thread(listenLoop);
        listenThread.IsBackground = true;
        status = new Thread(checkIfOnline);
        status.IsBackground = true;
        threadsActive = true;
        localEndPoint = new IPEndPoint(IPAddress.Parse("129.59.79.65"), 3000);
        listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        listenThread.Start();
        status.Start();
        textBox1.AppendText("Threads/Connections Restarted Successfully" + Environment.NewLine);
    }

如何在断开连接后重用或重新连接到同一端口上的套接字?

不要绑定客户端套接字。只有服务器端口是重要的。

在服务器端,只需保持侦听套接字侦听。当监听套接字接受连接时,它返回一个代表该连接的套接字。当检测到连接丢失时,关闭相应的连接套接字,但保持侦听套接字运行。

顺便说一句,在我看来,检测连接丢失的最好方法是定期发送数据(双向)。

我的博客上有一个TCP/IP . net常见问题解答。它是。net,但是一般的概念适用于任何TCP/IP场景。

详细阐述Stephen Cleary的精彩回答。在我们创建并绑定它之后,服务器开始侦听。控制进入无限循环。客户端连接到服务器。如果我们现在拔掉Internet,客户端抛出一个异常,这将使我们返回到无限循环的顶部,在那里我们等待网络连接,然后再尝试接受另一个连接。

private void ListenForIncomingHttpRequests()
{
    AwaitNetworkAvailability();
    // create
    var serverSocket = 
        new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    // bind
    var localEndpoint = new IPEndPoint(IPAddress.Any, port: 12000);
    serverSocket.Bind(localEndpoint);
    // listen
    serverSocket.Listen(backlog: 25);
    while (true)
    {
        AwaitNetworkAvailability();
        try
        {
            // client connects to the server
            using (var clientSocket = serverSocket.Accept())
            {
                ProcessServerSocketRequest(clientSocket);
            }
        }
        catch (Exception ex)
        {
            _logger.Write(ex.ToString());
        }
    }
}

这篇文章似乎清楚地解释了这个原理:迭代服务器程序中的主动和被动关闭

程序A启动主动关闭,程序B启动主动关闭被动关闭。当一个程序调用关闭套接字函数时,TCP协议层发送一个称为FIN (FINish)的段。当程序B接收到最后的确认段,它知道所有的数据都有了已成功转帐,项目A已收到处理FIN段。程序B的TCP协议层可以然后安全地删除程序占用的资源套接字。程序A的TCP协议层发送一个确认到它从程序B接收到的FIN段,而不是程序A的TCP协议层不知道ACK段是否到达程序B TCP协议层。它必须等待一段合理的时间查看程序B的FIN段是否被重传,表明程序B从未收到最后的ACK段程序A,在这种情况下,程序A必须能够重传最后的ACK段。在此之前程序A套接字不能被释放一段时间过去了。时间段定义为的两倍最大分段寿命,通常在1 - 4分钟范围内;