gpt4 book ai didi

c++ - GetQueuedCompletionStatus 继续在关闭的套接字上选择事件

转载 作者:行者123 更新时间:2023-11-30 04:54:50 25 4
gpt4 key购买 nike

IOCP 服务器使用 WebSocket 连接。当浏览器发送关闭帧时,服务器删除这个客户端,closesocket函数调用客户端的对象析构函数。但即使在套接字关闭后,GetQueuedCompletionStatus 函数仍会继续从此套接字中选择事件。当然结果是false,传输了0字节,但是Client ptr和OVERLAPPED ptr不为NULL,GetLastError返回1236(ERROR_CONNECTION_ABORTED)。 .. 所以是的,它被中止了,closesocket 被调用了......但为什么它还在这里???以及如何停止接收这种“无用”的事件?我可以在 thead 的循环中调用 continue,但如果该函数将永远选择这个已删除的客户端,则会浪费 CPU 时间。

这是工作线程循环的一部分:

while(WAIT_OBJECT_0 != WaitForSingleObject(EventShutdown, 0)){
DWORD BytesTransfered = 0;
OVERLAPPED *asyncinfo = nullptr;
client *Client = nullptr;
BOOL QCS = GetQueuedCompletionStatus(hIOCP, &BytesTransfered, (PULONG_PTR)&Client, &asyncinfo, INFINITE);
if(!Client ) break;

switch( QCS * (BytesTransfered > 0) * Client->OpCode() ){
case OP_TYPE_RECV:{
.....
switch( recv_buf[0] &0xFF ){
....
case FIN_CLOSE:
printf("FIN_CLOSE on client %u\n", Client->Socket());
default:{
RemoveClient(Client);
break;
}
}
}
case OP_TYPE_SEND:{
...
}
default:{
printf("Client %u (%lu bytes transferred, QCS is %d)\n", Client->Socket(), BytesTransfered, QCS);
break;
}

客户端的析构函数:

client::~client(){
while(!HasOverlappedIoCompleted(&asyncinfo)) Sleep(0);
closesocket(socket);
if( a_ctx ) delete a_ctx;
if( q_ctx ) delete q_ctx;
delete [] data_buffer;
printf("Client %u deleted\n", socket);
}

...和服务器的日志:

Client 296 from 127.0.0.1 (agent 1987)
Client 308 from 127.0.0.1 (supervisor)
Client 324 from 127.0.0.1 (supervisor)
TOTAL: 3 client(s)
Sending 33278 bytes to 324
Send finished for 324
Send finished for 308
Sending 40529 bytes to 324
Send finished for 324
Sending 41128 bytes to 324
Send finished for 324
Sending 40430 bytes to 324
Send finished for 324
FIN_CLOSE on client 324
Client 324 deleted
Client 324 (0 bytes transferred, QCS is 0)
Client 324 (0 bytes transferred, QCS is 0)
Client 324 (0 bytes transferred, QCS is 0)
Client 324 (0 bytes transferred, QCS is 0)
Client 324 (0 bytes transferred, QCS is 0)

看到“324(传输了 0 个字节,QCS 为 0)”?套接字 324 已关闭。为什么它发生在析构函数的消息“Client 324 deleted”之后?

最佳答案

我认为您没有包含足够的代码来获得完整的图片,但这一行看起来很可疑:

switch( QCS * (BytesTransfered > 0) * Client->OpCode() ){

由于几个原因,这是有问题的。首先,GetQueuedCompletionStatus 不保证在成功时返回 1。 MSDN 只 promise 它将返回非零值。因此,依赖于成功案例的特定值(value)是有风险的。其次,您无法区分失败的调用和返回 0 字节的成功调用。您应该真正分离管理出队和调度特定 I/O 事件的逻辑。这将使您的代码更易于理解和维护。

您还必须记住,每个 socket 都有两个侧面。在用户空间中有与之关联的结构和套接字句柄,然后是管理低级细节的内核对象。仅仅因为您在用户端关闭了您的句柄并不意味着内核对象消失了。内核对象被引用计数并且通常会持续到涉及这些对象的所有 I/O 完成为止。

这就是为什么从程序的角度来看,在套接字被“销毁”后,您仍然可以获得套接字的 I/O 通知。特别是对于套接字,关闭序列将在您关闭句柄后发生(因为在此之前您没有明确关闭套接字)。

不是为了响应特定消息而销毁 Client 对象,只需关闭套接字句柄并清理其他结构以响应中止通知。您还可以考虑正常断开连接而不是中止连接。

关于c++ - GetQueuedCompletionStatus 继续在关闭的套接字上选择事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53393101/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com