Reputation: 441
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
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