套接字通信不同步

时间:2015-03-17 13:50:06

标签: c++ sockets tcp winsock2

我正在使用winsock2 api,tcp套接字与服务器和客户端。 我正在使用阻止发送和recv。 沟通是这样的: 服务器向客户端发送查询,客户端回复。 每个查询都是1024字节缓冲区,客户端也使用相同大小的缓冲区。 对于每个查询和回复,要发送的实际数据可能不同。

我观察到的是,有时,通信不同步。 服务器接收一些垃圾数据。即使recv调用是阻塞的,它仍然会在recv缓冲区中收到一些垃圾数据。

为什么会出现这种行为? 解决方案是什么?

代码段:

SOCKET ListenSocket=(SOCKET)arg;
int iResult;
int CMD_SIZE = 1024;
u_long iMode;
SOCKET ClientSocket;
CbClient *tempClient = NULL;

// Listen to incoming connetion
iResult = listen(ListenSocket, 5);
if (iResult == SOCKET_ERROR) 
{
    LOG(ERROR) << "Listen failed with error "<< iResult;
    AfxMessageBox(TEXT("Listen Failed..!"));
    closesocket(ListenSocket);
    return 1;
}
// Valid Socket
// Accept a client socket 
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) 
{
    LOG(ERROR) << "Client Socket not created ";
    AfxMessageBox(TEXT("Accept Failed..!"));
    closesocket(ListenSocket);
    WSACleanup();
    return 1;
}
else
{   
    iMode = 0;
    iResult = ioctlsocket(ClientSocket, FIONBIO, &iMode);
    if (iResult != NO_ERROR)
    {
        LOG(ERROR) << "IoctlSocket failed with error "<< iResult;
    }

    //disable nagle
    char value = 1;
    if(setsockopt(ClientSocket, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)) == 0)
    {
        LOG(DEBUG) << "Disabled Nagle's Algorithm.";
    }

    int serverVerion          = SERVER_VERSION_NUMERIC;
    int clientVersion         = 0;
    char ver[CMD_SIZE]       = {0};
    char recvbuf[CMD_SIZE]   = {0};

    // Send Server Version
    sprintf_s(ver, "%d", serverVerion);
    iResult = send(ClientSocket, ver, CMD_SIZE, 0);
    // Receive client version
    ZeroMemory(recvbuf,CMD_SIZE);
    iResult=recv(ClientSocket, recvbuf, CMD_SIZE, 0);
    clientVersion = atoi(recvbuf);

    // Match Versions to Check Compatibility
    if(serverVerion != clientVersion)
    {
        LOG(ERROR) << "Client-Server Version does not match, Client denied "<< iResult;
        AfxMessageBox(_T("\nWarning : Client-Server Version does not match. Please Use Same Version"));
    }
    else
    {            
        // Send Server details
        char hostName[CMD_SIZE];
        DWORD dwCompNameLen = CMD_SIZE;

        if (0 != GetComputerNameA(hostName, &dwCompNameLen)) 
        {
            iResult = send(ClientSocket, hostName, CMD_SIZE, 0);
        }
        else
        {
            iResult = send(ClientSocket, "UNKNOWN", CMD_SIZE, 0);
        }
        // Receive Client Host Name
        ZeroMemory(recvbuf, CMD_SIZE);
        iResult=recv(ClientSocket, recvbuf, CMD_SIZE, 0);

        //Send Query and Recv replied back Results on seperate thread
    }
}

查询代码和Recv回复: sendCommand(clientSocket,databuffer,size,flags,extra params)和recvCommand(clientSocket,databuffer,size,flags,extra params)是send()和recv()调用的包装。

我的问题再现率是10次中的1次。

if( currentSendCmd->iCmd ==  CMD_ONE)
{
    // Send the Command over the Socket
    if(sendCommand(clientSocket, currentSendCmd, CMD_SIZE , 0, Client))
    {
        // Receiving response from client
        if(recvCommand(clientSocket, currentRecvCmd, CMD_SIZE , 0, Client))
        {
            if(currentRecvCmd->iCmd == CMD_ONE)
            {
                LOG(DEBUG) << "CMD_ONE command positive acknowledgement recieved";
                for(i = 0; i< Client->GetSomeCount(); i++)
                {
                    for(j = 0; j < CMD_ONE_REPLY_CMD_COUNT; j++)
                    {
                        // Receiving responses from client w.r.t. Gpu Info
                        if(recvCommand(clientSocket, currentRecvCmd, CMD_SIZE , 0, Client))
                        {
                            LOG(DEBUG) << "CMD_ONE command response no : " << i <<" recieved successfully";
                            flag = Client->UpdateClient(currentRecvCmd);
                            if(flag == FALSE)
                            {
                                LOG(DEBUG) << "CMD_ONE update no :"<<i<<" failed";
                            }
                        }
                        else
                        {   // Recv failed, updated in log
                            LOG(WARNING) << "CMD_ONE response no :"<<i<<" not recieved";
                        }
                    }// For CMD_ONE_REPLY_CMD_COUNT cmds
                }// For some count

                //Recieving CL_CMD_TWO info
                if(recvCommand(clientSocket, currentRecvCmd, CMD_SIZE , 0, Client))
                {
                    LOG(DEBUG) << "CL_CMD_TWO recieved successfully";
                    flag = Client->UpdateClient(currentRecvCmd);

                    if(flag == FALSE)
                    {
                        LOG(DEBUG) << "CL_CMD_TWO update failed";
                    }                                            
                }
                else
                {   // Recv failed, updated in log
                    LOG(WARNING) << "CL_CMD_TWO not recieved";
                }

                // Recieving CL_CMD_THREE Info                                            
                if(recvCommand(clientSocket, currentRecvCmd, CMD_SIZE , 0, Client))
                {
                    LOG(DEBUG) << "CL_CMD_THREE recieved successfully";
                    flag = Client->UpdateClient(currentRecvCmd);

                    if(flag == FALSE)
                    {
                        LOG(ERROR) << "CL_CMD_THREE Update failed";
                    }                                            
                }
                else
                {   // Recv failed, updated in log
                    LOG(ERROR) << "CL_CMD_THREE not recieved";
                }
            }//CL_CMD_ONE : End
            else
            {   // Recv failed, updated in log
                LOG(ERROR) << "Unrecognised command";
            } 
        }//CL_CMD_ONE send, recv if
        else
        {   // Recv failed, updated in log
            LOG(ERROR) << "Recv failed : CL_CMD_ONE";
        }                    
    }

1 个答案:

答案 0 :(得分:1)

您既未指定标记MSG_WAITALL也未检查recv()次呼叫的返回值。因此,您的recv()不仅可以在没有注意到的情况下成功收到部分消息(直到数据变成垃圾),但如果没有您注意到它也可能会失败。