首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++ WINSOCK在“攻击”后停止接受连接

C++ WINSOCK在“攻击”后停止接受连接
EN

Stack Overflow用户
提问于 2015-05-23 20:15:42
回答 2查看 1.4K关注 0票数 2

我在C++中有一个游戏服务器,我正在使用一个网络库,它在Windows中使用winsock。我一直在压力测试我的服务器,看看它一次能接受多少连接。当我使用我的游戏客户端连接时,它工作得很好,但是在我做了下面描述的压力测试之后,我的游戏客户端就不能再连接了。

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

我检查了库(参见下面的)的tcpaccept()函数,没有输出。由于某种原因,accept()在我对1000个连接的“攻击”之后停止接受连接。什么能让我的服务器停止接受连接呢?

下面是我的循环总结,它侦听并接受连接并关闭它们:

代码语言:javascript
复制
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(套接字)、CSocket::tcplisten(.)的定义和CSocket::tcpaccept(.):

代码语言:javascript
复制
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倍连接后出现异常。这是一个例外:

线程"main“中的异常( java.net.ConnectException: Connection拒绝:Connection at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79),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.(Socket.java:425) at java.net.Socket.(Socket.java:208) at Socket.java:528

EN

回答 2

Stack Overflow用户

发布于 2015-05-23 20:52:55

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

另一种选择可能是忽略这些套接字几分钟,并希望它们消失。当您完全没有响应时,客户端会调用closesocket,这意味着您不会招致time_wait。这通常是可行的,但并非总是如此。如果没有,则在后台缓慢地调用closesocket()。

如果您真的想要,您可以重置连接,详细信息请参阅LINGER (zero) - when it's required,但是重新设置连接是不正常的,所以一定要广泛阅读关于So_linger和teardown是如何工作的。

票数 1
EN

Stack Overflow用户

发布于 2015-05-23 22:40:34

事实证明,这个库有自己的关闭套接字的方法:

代码语言:javascript
复制
int closesock(int sockid)
{
    CSocket*sock = (CSocket*)sockets.item(sockid);
    if(sock == NULL)return -1;
    delete sock;
    sockets.set((int)sockid, NULL);
    return 1;
}

因此,它通过套接字列表中的sockID获取当前套接字。然后,如果sockID与有效的套接字相关,则删除sock对象并在套接字列表中将其设置为NULL。

问题是,我只是调用closesocket(sockID)而不是closesock(sockID),后者执行了关闭套接字所需的必要操作。

谢谢大家的帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30417144

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档