C++ WINSOCK tcpaccept 在 "attack"之后停止接受连接

标签 c++ sockets winsock ddos

我有一个用 C++ 编写的游戏服务器,我正在使用一个网络库在 Windows 中使用 winsock。 我一直在对我的服务器进行压力测试,看看它一次可以接受多少个连接。当我使用我的游戏客户端连接时它工作正常,但在我进行如下所述的压力测试后我的游戏客户端无法再连接。

压力测试是,我使用一个简单的循环程序连接到我的服务器大约 1000 次,该循环只启动与我的游戏服务器的 tcp 连接并立即关闭它。他们都联系在一起。然后,之后,我尝试连接我的游戏。游戏根本无法连接。

我检查了库中的 tcpaccept() 函数(见下文),没有输出。出于某种原因,accept() 在我“攻击”了 1000 个连接后停止接受连接。 什么可能会使我的服务器停止接受连接?

这是我对监听和接受连接并关闭它们的循环的总结:

bool serverIsOn = true;
double listen = tcplisten(12345, 30000, 1);
setnagle(listen, true);

...

while(serverIsOn){
    double playerSocket = tcpaccept(listen, 1);
    if(playerSocket > -1){
        cout << "Got a new connection, socket ID: " << playerSocket << endl;

        //add their sockID to list here!
        addSockIDToList(playerSocket);

    }

    //Loop through list of socks and parse their messages here..
    //If their message size == 0, we close their socket via closesocket(sockID);
    loopThroughSocketIdsAndCloseOnLeave();
}

cout << "Finished!" << endl;

这是 tcplisten、tcpaccept、CSocket::CSocket(SOCKET)、CSocket::tcplisten(...) 和 CSocket::tcpaccept(...) 的定义:

double tcplisten(int port, int max, int mode)
{
    CSocket* sock = new CSocket();
    if(sock->tcplisten(port, max, mode))
        return AddSocket(sock);
    delete sock;
    return -1;
}

double tcpaccept(int sockid, int mode)
{
    CSocket*sock = (CSocket*)sockets.item(sockid);
    if(sock == NULL)return -1;
    CSocket*sock2 = sock->tcpaccept(mode);
    if(sock2 != NULL)return AddSocket(sock2);
    return -1;
}

...

CSocket::CSocket(SOCKET sock)
{
    sockid = sock;
    udp = false;
    format = 0;
}

bool CSocket::tcplisten(int port, int max, int mode)
{
    if((sockid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) return false;
    SOCKADDR_IN addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(port);
    if(mode)setsync(1);
    if(bind(sockid, (LPSOCKADDR)&addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
    {
        closesocket(sockid);
        return false;
    }
    if(listen(sockid, max) == SOCKET_ERROR)
    {
        closesocket(sockid);
        sockid = INVALID_SOCKET;
        return false;
    }
    return true;
}


CSocket* CSocket::tcpaccept(int mode)
{
    if(sockid == INVALID_SOCKET) return NULL;
    SOCKET sock2;
    if((sock2 = accept(sockid, (SOCKADDR *)&SenderAddr, &SenderAddrSize)) != INVALID_SOCKET)
    {
        //This does NOT get output after that 1000-'attack' test.
        std::cout << "Accepted new connection!" << std::endl;
        CSocket*sockit = new CSocket(sock2);
        if(mode >=1)sockit->setsync(1);
        return sockit;
    }

    return NULL;
}

在我的 1000 次连接压力测试后,我该怎么做才能弄清楚为什么 accept() 不再接受连接?这与我在完成连接后关闭连接的方式有关吗?当我这样做时,我所做的只是调用:closesocket(sockID)

请询问任何其他需要的代码!

编辑: 我刚刚注意到我的“压力测试”java 程序 在连接了大约 668 次 后出现异常。这是异常(exception)情况:

Exception in thread "main" java.net.ConnectException: Connection refused: connect
    at java.net.DualStackPlainSocketImpl.connect0(Native Method)
    at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:579)
    at java.net.Socket.connect(Socket.java:528)
    at java.net.Socket.<init>(Socket.java:425)
    at java.net.Socket.<init>(Socket.java:208)
    at sockettest.SocketTest.main(SocketTest.java:63)
Java Result: 1

最佳答案

因为您的服务器端正在关闭套接字,它们很可能会在 time_wait 中等待几分钟。 Windows 有各种参数控制最大套接字和各种状态。我猜您的程序会在几分钟后重新开始运行,并且事件查看器中可能会出现一些警告。

另一种方法可能是简单地忽略这些套接字几分钟,并希望它们消失。也就是说,当您根本不响应时,客户端会调用 closesocket,这意味着您不会招致 time_wait。这通常有效,但并非总是如此。如果他们不这样做,那么您将在后台缓慢地对他们调用 closesocket()。

如果你真的想要,你可以重置连接,参见 TCP option SO_LINGER (zero) - when it's required有关详细信息,但重置连接是不正常的,因此一定要广泛阅读有关 So_linger 以及 tcp teardown 的工作原理。

关于C++ WINSOCK tcpaccept 在 "attack"之后停止接受连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30417144/

相关文章:

java - 如何从客户端-服务器套接字连接读取响应?

c++ - Visual C、WinSock HTTP Req 和非 Windows

c++ - Sendto 函数返回错误 - Windows 上的 UDP 套接字

c++ - 具有 3 个类别的 OpenCV SVM 预测置信度

c# - 同一文件中的文本和二进制数据

C++ 慢,python 快? (就开发时间而言)

c++ - boost asio async_write 不会在断开连接的客户端上生成损坏的管道或其他错误

C编程套接字缓冲区

c++ - 数据类型与模板参数不同的模板对象

c - Windows 上多线程应用程序中非阻塞服务器/监听套接字的最佳方法?