使用IOCP时如何关闭套接字?
我有一个使用IOCP的服务器应用程序。我想知道关闭使用IOCP时如何关闭套接字?,c,sockets,winapi,winsock,iocp,C,Sockets,Winapi,Winsock,Iocp,我有一个使用IOCP的服务器应用程序。我想知道关闭套接字的正确方法是什么 如果我只是调用closesocket()(对于句柄为12345的SOCKET),并且该SOCKET具有挂起的IO操作(例如:挂起的WSARecv()请求),则可能发生以下情况: 我调用closesocket(),这将破坏套接字 我接受另一个套接字,其句柄与12345相同 我使用12345句柄为SOCKET定义挂起的WSARecv()完成数据包。现在我假设这个完成数据包是针对当前SOCKET,句柄是12345,但实际上是针
套接字的正确方法是什么
如果我只是调用closesocket()
(对于句柄为12345
的SOCKET
),并且该SOCKET
具有挂起的IO操作(例如:挂起的WSARecv()
请求),则可能发生以下情况:
- 我调用
closesocket()
,这将破坏套接字
- 我接受另一个
套接字
,其句柄与12345
相同
- 我使用
12345
句柄为SOCKET
定义挂起的WSARecv()
完成数据包。现在我假设这个完成数据包是针对当前SOCKET
,句柄是12345
,但实际上是针对先前关闭的SOCKET
(这是这种方法的主要问题)
所以这显然是一个糟糕的方法
第二种似乎正确的方法是:
- 我将一个
struct
实例与每个SOCKET
关联。struct
有以下成员:一个名为int
的number\u挂起的操作
,一个名为的boolean
的套接字正在关闭
- 当我为
SOCKET
发出IO操作时(例如:aWSASend()
请求),我通过1
增加挂起IO操作的数量,当我为SOCKET发出完成包时,我通过1
减少挂起IO操作的数量
- 现在,当我想关闭
SOCKET
时,我并不是简单地调用closesocket()
,而是调用CancelIOEx()
来取消SOCKET
的所有挂起的IO操作,我还将是否正在关闭的设置为true
- 当我准备发出另一个IO操作(例如:a
WSASend()
请求)时,我会检查的值是否正在关闭
,如果它是true
,我就不会发出IO操作
- 现在,我只需等待所有的完成数据包出列,当
挂起的IO操作的数量达到0
并且套接字是否关闭设置为true
,我调用closesocket()
当然,我会有比赛条件,所以我会使用关键部分
第二种方法是关闭套接字的正确方法,还是有更好的方法?我的客户机服务器应用程序中也有类似问题。我想我没有比赛,没有破败保护,也没有关键部分。不过也有一些折衷办法
- 一次只能有一个WSARecv()。多个缓冲区——可能是,但只有一个WSARecv()。WSARecv完成(可能是内联的),数据包从完成端口弹出,我快速检查得到的数据并发出另一个WSARecv()
- 我有一个标志(实际上,一个只能上升的计数器)表示插座正在关闭。计数器,因为我可能同时决定在两个不同的位置终止套接字
- 在关闭设置后,我调用shutdown(),然后调用CancelIoEx(),这将破坏之前发布的WSARecv()
- CancelIoEx和WSARecv()的完成之间存在竞争——我通过在发出WSARecv()之前仔细检查套接字是否关闭来消除这一竞争。即使发生竞争,WSARecv()也注定会失败,因为shutdown()
- 该结构是refcounted,其中一个ref由接收状态机持有,一个ref由ptr的每个合法所有者持有(如中的潜在发送方)。如果您有一个合法的引用,您可以制作一个副本,并将其交给其他人(这里的副本不同于详细的引用,因为它们的AddRef()可能会失败)。我只在ref为零时关闭socket(),因为我不能保证没有线程通过了所有检查并即将发出WSARecv/WSASend
“第二种方法”-是的,现在你走上了正确的道路。然而,这里不需要关键部分,所有这些都可以通过联锁操作完成<代码>联锁增量
/联锁增量
用于挂起的IO操作数
。about插座是否处于关闭状态
不够好。这里真的需要耗损保护(插座手柄)。在用户模式下,没有用于此的api,但只需自行实现即可<代码>如果(AcquisiteUndownProtection()){WSASend();ReleaseRundownProtection();}
当需要closesocket时-启动rundown(但不要在此处等待),并在它完成关闭句柄时。关于请注意,传递给I/O操作的重叠
结构可以是包含上下文信息的较大结构的第一个成员,例如,指向与套接字关联的结构的指针。这样可以节省您在表或类似文件中查找套接字句柄的时间,这反过来意味着,如果方便的话,没有令人信服的理由不关闭套接字。RbMm很高兴在这里看到其他驱动程序开发人员:-)。看起来你有一些使用微型过滤器的工作经验。事实上,我确实在同一个代码库中在userland中实现了rundown保护,并考虑将其用于这个目的(除了其他一些目的之外)——在进行了一些测量之后,我决定不使用它。Rundown保护似乎更适合于引用寿命较长且不会生成引用(或者更容易处理AddRef()的失败)的情况,因此当您有一个明确的所有者时,您可以保证只有一个调用BeginRundown。Harry Johnson,我看不出当另一个线程进入WSARecv/WSASend()时调用closesocket()时,这种方法如何保证正确性。至于包含超过