Anurag Daware
Anurag Daware

Reputation: 441

Socket communication goes out of sync

I am using winsock2 api, tcp sockets with a server and a client. I am using blocking send and recv. Communication is like this: Server sends query to client and client replies back. Each query is of 1024 bytes buffer and client also uses same sized buffer. Actual data to be sent can be different for each query and reply.

What I am observing is, sometimes, communication goes out of sync. Server receives some garbage data. Even though recv call is blocking, it goes ahead with some garbage data received in recv buffer.

Why is the reason of this behaviour? What is the solution for this?

Code Snippet:

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
    }
}

Code to Query and Recv reply : sendCommand(clientSocket, databuffer, size, flags, extra params) and recvCommand(clientSocket, databuffer, size, flags, extra params) are wrapper over send() and recv() calls.

My problem reproduction rate is ~ 1 out of 10 times.

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";
        }                    
    }

Upvotes: 0

Views: 1321

Answers (1)

John Bollinger
John Bollinger

Reputation: 180161

You are neither specifying flag MSG_WAITALL nor checking the return value of your recv() calls. As a result, not only may your recv() successfully receive only a partial message without you noticing (until the data turn out to be garbage), but it may also fail without you noticing.

Upvotes: 1

Related Questions