我正在使用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";
}
}
答案 0 :(得分:1)
您既未指定标记MSG_WAITALL
也未检查recv()
次呼叫的返回值。因此,您的recv()
不仅可以在没有注意到的情况下成功收到部分消息(直到数据变成垃圾),但如果没有您注意到它也可能会失败。