我为套接字操作使用WinAPI编写了WinAPI服务。客户端和服务之间的通信很简单,连接到服务客户端后发送一些数据,然后服务发送响应。
服务端的主套接字(ListenSocket)如下所示:
SOCKET ListenSocket = socket(pAddrResult->ai_family, pAddrResult->ai_socktype, pAddrResult->ai_protocol);
/* err checking */
/* Setting socket I/O mode to non-blocking */
u_long nonBlockingMode = 1;
opResult = ioctlsocket(ListenSocket, FIONBIO, &nonBlockingMode);
/* err checking */选择-接受主套接字上的循环:
while(...)
{
if(select(0, &readSet, NULL, NULL, &timeout) == 1)
{
ClientSocket = accept(ListenSocket, NULL, NULL); // SOCKET type, declared in global scope.
/* err checking */
break;
}
}在中断循环服务之后,从ClientSocket开始读取,并且在该服务发送这个套接字上的响应之后:
int iSendResult = send(ClientSocket, (const char*) messageBuffer.getData(), messageBuffer.getSize(), 0);
/* err checking */
/* FIX sleep(50) */
int opResult = shutdown(ClientSocket, SD_BOTH);
/* err checking */
closesocket(ClientSocket);在closesocket()进程返回select-accept循环并等待其他连接之后。
我的问题是,有时客户端接收的数据不足,并获得“连接被远程主机关闭”的信息。经过调试和一些研究,我在MSDN上找到了以下说明:
使用SD_SEND或SD_BOTH的密闭或关机函数将在控制通道上发送释放信号。由于ATM使用了单独的信号和数据信道,释放信号有可能在最后一个数据到达其目的地之前到达远程端,从而导致该数据的丢失。一种可能的解决方案是在最后发送的数据与关机或关机函数调用ATM套接字之间设定足够的延迟。
延迟您说微软?(好的,我已经实现了短延迟(/* FIX sleep(50) */),问题已经解决了。
但我一点也不满意。我想删除这个sleep(),并确保缓冲区在发送后被完全刷新,并且我可以安全地使用shutdown()和closesocket()。
我试图使主套接字非阻塞,希望send()将阻止直到完成,但我错了-没有效果。
在没有sleep()的情况下,我还能做些什么让它工作吗?
发布于 2018-01-22 11:34:27
我决定使用的解决方案:
1)只使用shutdown()调用SD_SEND,而不是在send()之后调用SD_BOTH。
2)实现循环,等待非阻塞recv()返回0,这意味着客户端优雅地关闭套接字。方法在套接字接收到数据、执行最大重试或发生其他错误时出现错误退出。
while (true)
{
int result = recv(ClientSocket, &buff, sizeof(buff), 0);
if (result == 0)
return 0; // Client gracefully closed connection.
else if (result > 0)
return -1; // Received unexpected data instead of socket closure
else
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
if (retryNumber++ == MAX_RETRY_NUMBER)
return -1; // Client didn't close socket within specified time
sleep(10); // wait 10ms
}
else
return -1; // Unexpected error occured
}
}发布于 2018-01-18 18:24:42
常见的方法是,一个部分只发出SD_SEND关机,然后对等端将以0长度读取结束,并且能够关闭,因为通信通道上仍然不能保留任何内容。在我的另一个answer上可以找到一个更详细的解释和一些参考。
https://stackoverflow.com/questions/48326635
复制相似问题