首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在套接字发送()后不久关闭()和closesocket()

在套接字发送()后不久关闭()和closesocket()
EN

Stack Overflow用户
提问于 2018-01-18 17:00:16
回答 2查看 2.2K关注 0票数 1

我为套接字操作使用WinAPI编写了WinAPI服务。客户端和服务之间的通信很简单,连接到服务客户端后发送一些数据,然后服务发送响应。

服务端的主套接字(ListenSocket)如下所示:

代码语言:javascript
复制
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 */

选择-接受主套接字上的循环:

代码语言:javascript
复制
while(...)
{
    if(select(0, &readSet, NULL, NULL, &timeout) == 1)
    {
        ClientSocket = accept(ListenSocket, NULL, NULL); // SOCKET type, declared in global scope.
        /* err checking */
        break;
    }
}

在中断循环服务之后,从ClientSocket开始读取,并且在该服务发送这个套接字上的响应之后:

代码语言:javascript
复制
 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()的情况下,我还能做些什么让它工作吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-01-22 11:34:27

我决定使用的解决方案:

1)只使用shutdown()调用SD_SEND,而不是在send()之后调用SD_BOTH

2)实现循环,等待非阻塞recv()返回0,这意味着客户端优雅地关闭套接字。方法在套接字接收到数据、执行最大重试或发生其他错误时出现错误退出。

代码语言:javascript
复制
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
    }
}
票数 1
EN

Stack Overflow用户

发布于 2018-01-18 18:24:42

常见的方法是,一个部分只发出SD_SEND关机,然后对等端将以0长度读取结束,并且能够关闭,因为通信通道上仍然不能保留任何内容。在我的另一个answer上可以找到一个更详细的解释和一些参考。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48326635

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档