Winsock - 客户端断开连接,关闭套接字循环/最大连接数

Posted

技术标签:

【中文标题】Winsock - 客户端断开连接,关闭套接字循环/最大连接数【英文标题】:Winsock - Client disconnected, closesocket loop / maximum connections 【发布时间】:2015-07-18 23:04:25 【问题描述】:

我正在学习 Winsock,并尝试创建一些简单的程序来了解它。我设法创建了可以处理多个连接的服务器,还根据所有教程管理它们和客户端,它正在按预期工作,但是:

我尝试创建循环,检查是否有任何客户端断开连接,如果断开连接,我想关闭它。

我设法编写了一些东西来检查套接字是否已断开连接,但它不会同时连接 2 个或多个套接字

如果每个客户端已断开并关闭套接字,任何人都可以给我答复如何通过每个客户端进行工作循环检查?这一切都是为了让最大客户端一次连接到服务器。提前致谢。

while (true)

    ConnectingSocket = accept (ListeningSocket, (SOCKADDR*)&addr, &addrlen);
    if (ConnectingSocket!=INVALID_SOCKET)
    
        Connections[ConnectionsCounter] = ConnectingSocket;
        char *Name = new char[64];
        ZeroMemory (Name,64);
        sprintf (Name, "%i",ConnectionsCounter);
        send (Connections[ConnectionsCounter],Name,64,0);
        cout<<"New connection !\n";
        ConnectionsCounter++;
        char data;
        if (ConnectionsCounter>0)
        
            for (int i=0;i<ConnectionsCounter;i++)
            
                 if (recv(Connections[i],&data,1, MSG_PEEK))
                 
                     closesocket(Connections[i]);
                     cout<<"Connection closed.\n";
                     ConnectionsCounter=ConnectionsCounter-1;
                 
            
        
    
    Sleep(50);

【问题讨论】:

How can I check is a socket is still open? 的可能重复项 您提供的示例代码没有提供足够的细节来提供帮助。提供的代码部分是循环调用的函数吗?您在调试器中看到了什么? @advent 为什么拒绝我对您的示例代码的编辑?它的格式不可读。 我不认为这是必要的编辑。它是完整的代码,无需声明套接字、绑定和侦听。我将添加整个循环。 可能对你有用:msdn.microsoft.com/en-us/library/windows/desktop/… 【参考方案1】:

您似乎想使用单个线程管理多个连接。对? 简单来说socket通信有两种方式,阻塞和非阻塞。默认是块模式。让我们专注于您的代码:

for (int i=0;i<ConnectionsCounter;i++)

    if (recv(Connections[i],&data,1, MSG_PEEK))
    
        closesocket(Connections[i]);
        cout<<"Connection closed.\n";
        ConnectionsCounter=ConnectionsCounter-1;
    

在上面的代码中,您调用了 recv 函数。它将阻塞,直到对等方向您发送消息,或对等方关闭链接。因此,如果您现在有两个连接,即 Connections[0] 和 Connections[1]。如果你是recv Connections[0],同时Connections[1] 断开了,你不知道。因为您在 recv(Connections[0]) 处阻塞。当 Connections[0] 向您发送消息或关闭套接字时,然后循环继续,最后您检查它是否断开连接,即使它在 10 分钟前断开连接。

要解决这个问题,我认为您需要一本书Microsoft Windows 网络编程。有一些方法,例如一线程一套接字模式、异步通信模式、非阻塞模式等。


忘了指出bug,这里注意一下:

closesocket(Connectons[i]);
cout<<"Connection closed.\n";
ConnectionsCounter=ConnectionsCounter-1;

让我举一个例子来说明它。现在我们有两个索引为 0 和 1 的连接,那么 ConnectionsCount 应该是 2,对吧?当 Connections[0] 断开连接时,ConnectionsCounter 从 2 变为 1。并且循环退出,新客户端连接,您将新客户端套接字保存为 Connections[ConnectionsCounter(=1)] = ConnectingSocket;哎呀,有一个错误。因为断开连接的套接字的索引是 0,而索引 1 被另一个链接使用。您正在重用索引 1。

为什么不尝试使用矢量来保存套接字。

希望对你有帮助~

【讨论】:

是的,我使用的是单线程。我成功了,但我在这个多重连接检查中遗漏了一些东西。使用 recv 使我的服务器只能专注于单个客户端,而其他客户端必须等到另一个客户端关闭。 这就是我的想法,我看到类 Socket 有一个名为 isDisconnected 的方法或类似的方法,所以使用它可能是个好主意。我还有很多东西要学,我也有很多想法如何尝试实现这些和其他东西,但我需要一些时间才能理解它是如何工作的并能够流利地处理它。感谢您的关注和良好的建议,这真的很有帮助。 从头到尾完全不正确。如果在您检查这个时另一个对等方断开了连接,您稍后会在检查时发现它。断开连接事件不仅被丢弃。检测对等断开连接的唯一方法是尝试从套接字读取。没有其他套接字方法可以告诉您这一点。不要在这里发布错误信息。 是否有冲突?如果线程在等待recv(connections[0]...)返回,而connections[1]断开,此时程序并不知道,直到connections[ 0] 发送数据或断开连接然后循环继续到 recv(connections[1]...) 并返回 -1,现在我们知道连接 [1] 断开连接。有什么问题吗? 实际上循环正在工作,即使它正忙于其他套接字。如果我快速关闭 10 个客户端,在关闭繁忙的客户端后,我会收到 11 个断开连接,连接消息。

以上是关于Winsock - 客户端断开连接,关闭套接字循环/最大连接数的主要内容,如果未能解决你的问题,请参考以下文章

WinSock TCP 长连接(while循环)

客户端断开连接后,我是不是必须关闭服务器端的套接字?

为啥我的 TCP 服务器套接字在一个客户端断开连接后关闭?

使用 WinSock 客户端/服务器应用程序重用套接字

服务器套接字只能连接几次(Winsock C++)

Winsock编程基础2(UDP流程)