【发布时间】:2014-11-01 05:58:51
【问题描述】:
我通过封装 Winsock2 API 的套接字库使用非阻塞套接字。 WSAAsyncSelect() 函数用于将套接字通知发送到窗口。 (应用程序是单线程的)。
我正在尝试为打开的客户端套接字实现以下目标:
- 向服务器发送最终消息
- 关闭套接字并销毁窗口
我不想让服务器阻塞等待ACK 我的最后一条消息,因为这会给我的代码用户带来另一个延迟/失败点。这对我的协议来说不是一个重要的信息,只是一个不错的选择。
目前,我的代码最终调用 Winsock2 send() 来发送最终消息,然后调用 closesocket()。但是,我的 TCP 流(由 Wireshark 观察)看起来像:
// Calling send():
Me -> Host: [PSH, ACK]
// Calling closesocket():
Me -> Host: [FIN, ACK]
// Just after that:
Host -> Me: [ACK]
Host -> Me: [ACK]
Host -> Me: [ACK] Len=1380 // A response to my sent packet, that I don't care about
Me -> Host: [RST, ACK]
Host -> Me: [RST]
Host -> Me: [PSH, ACK] // Retransmission of that response
Me -> Host: [RST]
因此,Windows 发送了两个 RST 请求。我相信这是因为套接字在发送FIN 后收到了一条消息,因此它决定RST 是必要的,但随后主机将其解释为重传请求。
如果我将代码更改为在调用closesocket 之前稍等片刻,那么跟踪看起来会非常不同:我的一端只发送[FIN, ACK],另一端发送[FIN, ACK],但没有RST。
我的问题是:我怎样才能整洁地关闭我的套接字(即避免 RST 交换)而不必阻塞?
【问题讨论】:
-
我不确定我是否理解;既然这是一个非阻塞套接字,为什么最终读取需要是阻塞读取?
-
@HarryJohnston 我破坏了套接字通知将要进入的模式窗口,因此无法进行非阻塞读取
-
啊。您能否改为隐藏窗口,并在完全关闭连接后将其销毁?
-
@HarryJohnston 也许,我会调查的。我的代码在一个 DLL 中,该 DLL 被加载到我无法控制的代码进程中,因此任何接受消息的非模态窗口都依赖于具有健全的消息循环的第三方......而且我对依赖它持谨慎态度一般 :) 但是感谢您的想法,它可能仍然可行。