第一个客户端在多套接字winsock服务器中是滞后的



我有一个WinSock服务器设置,它正确地接受客户端并传递适当的信息。服务器接收两个客户机,接收一个256字节的固定大小的缓冲区,存储它,然后将另一个缓冲区转发给客户机。(即。Client1发送它的缓冲区,服务器保存它,然后向Client1发送client2的缓冲区)。

每当client1更改其缓冲区时,client2大约需要4秒才能接收到更改。如果client2进行了更改,client1几乎立即接收到更新(少于0.1s)。

Nagle的算法是禁用的,我已经尝试改变服务器处理请求的顺序,但client1总是滞后。数据总是完好无损地显示出来,但耗时太长。下面是服务器用来处理数据的循环:

for(;;)
{   
    // check if more clients can join
    if (numClients < MAX_CLIENTS)
    {
        theClients[numClients] = accept(listeningSocket, NULL, NULL);
        if (theClients[numClients] == INVALID_SOCKET)
        {
            nret = WSAGetLastError();
            JBS::reportSocketError(nret, "server accept()");
            closesocket(listeningSocket);
            WSACleanup();
            exit(0);
        }
        // disable Nagle's algorithm
        int flag = 1;
        int result = setsockopt(theClients[numClients], IPPROTO_TCP, TCP_NODELAY, 
            (char *) &flag, sizeof(int));
        if (result < 0)
        {
            nret = WSAGetLastError();
            JBS::reportSocketError(nret, "client connect()");
            closesocket(theClients[numClients]);
            WSACleanup();
        }
        // make the socket non-blocking
        u_long iMode = 1;
        ioctlsocket(theClients[numClients],FIONBIO, &iMode);
        cout << "Client # " << numClients << " connected." << endl;
        numClients++;
        started = true;
    }
    else
    {
        // we've received all the connections, so close the listening socket
        closesocket(listeningSocket);
    }
    // process client2
    if (theClients[1] != INVALID_SOCKET)
    {
        memset(keys2, 0, 255);
        // receive the updated buffer
        nBytes = recv(theClients[1], keys2, sizeof(keys2), 0);
        receiveResult = WSAGetLastError();
        if ((receiveResult != WSAEWOULDBLOCK) && (receiveResult != 0))
        {
            JBS::reportSocketError(receiveResult, "server receive keys2()");
            shutdown(theClients[1],2);
            closesocket(theClients[1]);
            WSACleanup();
            exit(0);
            break;
        }
        // send client1's buffer to client2
        send(theClients[1],keys1,sizeof(keys1),0);
        sendResult = WSAGetLastError();
        if((sendResult != WSAEWOULDBLOCK) && (sendResult != 0))
        {
            JBS::reportSocketError(sendResult, "server send keys1()");
            shutdown(theClients[1],2);
            closesocket(theClients[1]);
            WSACleanup();
            exit(0);
            break;
        }
    }
    // process client1
    if (theClients[0] != INVALID_SOCKET)
    {
        memset(keys1, 0, 255);
        // receive the updated buffer
        nBytes = recv(theClients[0], keys1, sizeof(keys1), 0);
        receiveResult = WSAGetLastError();
        if ((receiveResult != WSAEWOULDBLOCK) && (receiveResult != 0))
        {
            JBS::reportSocketError(receiveResult, "server receive keys1()");
            shutdown(theClients[0],2);
            closesocket(theClients[0]);
            WSACleanup();
            exit(0);
            break;
        }
        // send client2's buffer to client1
        send(theClients[0],keys2,sizeof(keys2),0);
        sendResult = WSAGetLastError();
        if((sendResult != WSAEWOULDBLOCK) && (sendResult != 0))
        {
            JBS::reportSocketError(sendResult, "server send keys2()");
            shutdown(theClients[0],2);
            closesocket(theClients[0]);
            WSACleanup();
            exit(0);
            break;
        }
    }
    Sleep((float)(1000.0f / 30.0f));
}

客户端发送码

int nError, sendResult;
sendResult = send(theSocket, keys, sizeof(keys),0);
nError=WSAGetLastError();
if((nError != WSAEWOULDBLOCK) && (nError != 0))
{
    JBS::reportSocketError(sendResult, "client send()");
    shutdown(theSocket,2);
    closesocket(theSocket);
    WSACleanup();
}

我将您的代码粘贴在下面,其中包含一些内联注释,主要是因为我无法将其全部合理地放入注释中。如何确定从client1到client2的更改需要4秒钟?目视检查吗?这是否意味着Client1 &Client2在同一台机器上运行(没有不同的网络延迟问题需要担心)?

我突出显示了一些看起来不对的块。他们可能不是,这可能是因为你试图简化你发布的代码,你错过了一些位。对于您可能希望在哪些地方添加日志记录,我还提出了一些建议。如果套接字确实是非阻塞的,那么您应该很快从所有调用中返回并且无法读取数据,除非客户端已经发送了数据。如果你有4秒的延迟,那么问题可能是:

  • 客户端还没有发送…内格尔在客户端禁用了吗?如果是这样的话,我预计会发生连续的呼叫接收,没有数据。
  • 接收呼叫耗时太长…套接字是否真的处于非阻塞模式?
  • 发送呼叫耗时太长…套接字是否处于非阻塞模式,它是否被缓冲,客户端是否试图接收数据?

记录每段代码所花费的时间将有助于找到问题所在。

你可以得到时间,使用像这样的东西(从网上借来的):

 struct timeval tv;
 struct timezone tz;
 struct tm *tm;
 gettimeofday(&tv, &tz);
 tm=localtime(&tv.tv_sec);
 printf(" %d:%02d:%02d %d n", tm->tm_hour, tm->tm_min,
          m->tm_sec, tv.tv_usec);
代码:

for(;;)
{   

/* This block of code is checking the server socket and accepting
 * connections, until two? (MAX_CLIENTS isn't defined in visible code)
 * connections have been made.  After this, it is attempting to close
 * the server socket everytime around the loop.  This may have side
 * effects (although probably not), so I'd clean it up, just in case
 */
/* LOG TIME 1 */
    // check if more clients can join
    if (numClients < MAX_CLIENTS)
    {
        theClients[numClients] = accept(listeningSocket, NULL, NULL);
        if (theClients[numClients] == INVALID_SOCKET)
        {
            nret = WSAGetLastError();
            JBS::reportSocketError(nret, "server accept()");
            closesocket(listeningSocket);
            WSACleanup();
            exit(0);
        }
        // disable Nagle's algorithm
        int flag = 1;
        int result = setsockopt(theClients[numClients], IPPROTO_TCP, TCP_NODELAY, 
            (char *) &flag, sizeof(int));
        if (result < 0)
        {
            nret = WSAGetLastError();
            JBS::reportSocketError(nret, "client connect()");
            closesocket(theClients[numClients]);
            WSACleanup();
        }
        // make the socket non-blocking
        u_long iMode = 1;
        ioctlsocket(theClients[numClients],FIONBIO, &iMode);
        cout << "Client # " << numClients << " connected." << endl;
        numClients++;
/* This started variable isn't used, is it supposed to be wrapping 
 * this server code in an if statement?
 */
        started = true;
    }
    else
    {
        // we've received all the connections, so close the listening socket
        closesocket(listeningSocket);
    }
/* LOG TIME 2 */

    // process client2
    if (theClients[1] != INVALID_SOCKET)
    {
        memset(keys2, 0, 255);
        // receive the updated buffer
/* LOG TIME 3 */
        nBytes = recv(theClients[1], keys2, sizeof(keys2), 0);
/* LOG TIME 4 */
        receiveResult = WSAGetLastError();
        if ((receiveResult != WSAEWOULDBLOCK) && (receiveResult != 0))
        {
            JBS::reportSocketError(receiveResult, "server receive keys2()");
            shutdown(theClients[1],2);
            closesocket(theClients[1]);
            WSACleanup();
            exit(0);
            break;
        }
        // send client1's buffer to client2
/* LOG TIME 5 */
        send(theClients[1],keys1,sizeof(keys1),0);
/* LOG TIME 6 */
        sendResult = WSAGetLastError();
        if((sendResult != WSAEWOULDBLOCK) && (sendResult != 0))
        {
            JBS::reportSocketError(sendResult, "server send keys1()");
            shutdown(theClients[1],2);
            closesocket(theClients[1]);
            WSACleanup();
            exit(0);
            break;
        }
    }
    // process client1
/* If the client has been accepted (note that because this
 * is part of the same block of code, and there's no protection
 * around it, the first connection will process it's first
 * receive/send combination before the second socket has been accepted)
 */
    if (theClients[0] != INVALID_SOCKET)
    {
        memset(keys1, 0, 255);
        // receive the updated buffer
/* You're trying a receive against a non-blocking socket.  I would expect this
 * to fail with WSAEWOULDBLOCK, if nothing has been sent by the client, but
 * this block of data will still be sent to the client
 */
/* LOG TIME 7 */
        nBytes = recv(theClients[0], keys1, sizeof(keys1), 0);
/* LOG TIME 8 */
        receiveResult = WSAGetLastError();
        if ((receiveResult != WSAEWOULDBLOCK) && (receiveResult != 0))
        {
            JBS::reportSocketError(receiveResult, "server receive keys1()");
            shutdown(theClients[0],2);
            closesocket(theClients[0]);
            WSACleanup();
            exit(0);
            break;
        }
        // send client2's buffer to client1
/* The first time around the loop, you're sending the buffer to the
 * first connected client, even though the second client hasn't connected yet.
 * This will continue 30 times a second, until the second client connects.  Does
 * the client handle this correctly?
 */
/* LOG TIME 9 */
        send(theClients[0],keys2,sizeof(keys2),0);
/* LOG TIME 10 */
        sendResult = WSAGetLastError();
        if((sendResult != WSAEWOULDBLOCK) && (sendResult != 0))
        {
            JBS::reportSocketError(sendResult, "server send keys2()");
            shutdown(theClients[0],2);
            closesocket(theClients[0]);
            WSACleanup();
            exit(0);
            break;
        }
    }
    Sleep((float)(1000.0f / 30.0f));
}

客户端发送码

int nError, sendResult;
/* There's no recv / loop in this section
 */
sendResult = send(theSocket, keys, sizeof(keys),0);
nError=WSAGetLastError();
if((nError != WSAEWOULDBLOCK) && (nError != 0))
{
    JBS::reportSocketError(sendResult, "client send()");
    shutdown(theSocket,2);
    closesocket(theSocket);
    WSACleanup();
}

最新更新