在服务器套接字上获取随机10060(连接超时)错误

Tom*_*rdt 5 c++ sockets windows-8

我的软件的一些用户最近来找我,告诉我它在Windows 8上不起作用.经过调查后发现,由于一些奇怪的原因,我的服务器套接字并不总是接受连接,但让它们超时.

更奇怪的是:连接到localhost时也会发生这种情况,而不仅仅是在远程访问时.

"你试过什么?"

  • 显而易见的事情:关闭防火墙(没有效果),看看其他软件是否正常工作(确实如此),尝试修改随机代码行(没有效果).
  • 不太明显的东西:使用全局WSAStartup而不是每个客户端或服务器实例一个(没有效果).

提醒:完全相同的代码在Windows XP和Windows 7上运行正常,它也会影响localhost连接(不是硬件问题).此外,只有三分之一的连接失败,其余的工作正常.

好的,现在是一些真正的代码,因为它比所有这些单词更有用.

套接字设置:

int iResult;

struct addrinfo *result = NULL;
struct addrinfo hints;

ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;

// "Resolve" our localhost
iResult = getaddrinfo(NULL, port, &hints, &result);
if (iResult != 0) {
    printf("error (2) : %d\n", iResult);
    return false;
}

// Create the socket
listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (listenSocket == INVALID_SOCKET) {
    freeaddrinfo(result);
    printf("error (3) : %d\n", WSAGetLastError());
    return false;
}

// Bind it
iResult = bind(listenSocket, result->ai_addr, result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
    freeaddrinfo(result);
    closesocket(listenSocket);
    printf("error (4) : %d\n", WSAGetLastError());
    return false;
}

freeaddrinfo(result);

// Listen
iResult = listen(listenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
    closesocket(listenSocket);
    printf("%d\n", WSAGetLastError());
    return false;
}
Run Code Online (Sandbox Code Playgroud)

您可能已经看到,它几乎直接来自MSDN,应该没问题.此外,它适用于2/3的连接,所以我真的怀疑它是错误的设置代码.

接收者代码:

    if (listenSocket == INVALID_SOCKET) return false;
#pragma warning(disable:4127)
    fd_set fds;

    SOCKET client;
    do {
        FD_ZERO(&fds);
        FD_SET(listenSocket, &fds);

        struct timeval timeout;
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;
        if (!select(1, &fds, NULL, NULL, &timeout)) continue; // See you next loop!

        struct sockaddr_in addr;
        socklen_t addrlen = sizeof(addr);

        // Accept the socket
        client = accept(listenSocket, (struct sockaddr *)&addr, &addrlen);

        if (client == INVALID_SOCKET) {
            printf("[HTTP] Invalid socket\n");
            closesocket(listenSocket);
            return false;
        }

        // Set a 1s timeout on recv()
        struct timeval tv;
        tv.tv_sec = 1;
        tv.tv_usec = 0;
        setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));

        // Receive the request
        char recvbuf[513];
        int iResult;
        std::stringbuf buf;

        clock_t end = clock() + CLOCKS_PER_SEC; // 1s from now

        do {
            iResult = recv(client, recvbuf, 512, 0);
            if (iResult > 0) {
                buf.sputn(recvbuf, iResult);
            } else if (iResult == 0) {
                // Hmm...
            } else {
                printf("[HTTP] Socket error: %d\n", WSAGetLastError());
                break;
            }
        } while (!requestComplete(&buf) && clock() < end);
Run Code Online (Sandbox Code Playgroud)

此代码吐出"[HTTP]套接字错误:10060"错误,因此在其后面的任何代码都是相当无关紧要的.

select电话是因为有实际的循环做一些其他的事情为好,但我离开它,因为它没有插座相关.

更奇怪的是:根据Wireshark的说法,Windows似乎正在制造实际的网络错误:http://i.imgur.com/BIrbD.png

我一直试图解决这个问题一段时间了,我可能只是做了一些愚蠢的事情,所以我非常感谢你的所有答案.

Tom*_*rdt 4

我已经花了一整天的时间来解决这个恼人的问题,并通过从头开始重写整个服务器并以不同的方式实现它来最终解决它。我确实追踪到这个问题setsockopt似乎不再需要SO_RCVTIMEO很好,导致超时达到零秒,这使得随机连接超时。

我的新实现不再使用超时,现在只是非阻塞和异步的。效果很好,但需要更多代码。

我假设这只是 Windows 8 中的一个错误,将在发布之前通过更新修复。我怀疑微软是否想像这样改变 Berkeley Sockets API。