【发布时间】:2018-11-20 12:33:58
【问题描述】:
IOCP 服务器使用 WebSocket 连接。当浏览器发送关闭帧时,服务器deletes 这个客户端,closesocket 函数在客户端的对象析构函数中调用。但即使在套接字关闭后,GetQueuedCompletionStatus 函数仍会继续从该套接字中选择事件。当然结果是 false 和 0 字节传输,但客户端 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);
}
...和服务器的日志:
来自 127.0.0.1 的客户端 296(代理 1987)
来自 127.0.0.1 的客户端 308 (主管)
来自 127.0.0.1 的客户 324(主管)
总计:3 客户端
正在向 324 发送 33278 个字节
324 发送完成
308 发送完成
将 40529 字节发送到 324
发送完成 对于 324
发送 41128 字节到 324
发送完成对于 324
向 324 发送 40430 字节
324 发送完成
FIN_CLOSE on 客户端 324
客户端 324 已删除
客户端 324(已传输 0 个字节, QCS 为 0)
客户端 324 (0 字节传输,QCS 为 0)
客户端 324(0 字节传输,QCS 为 0)
客户端 324(0 字节 已传输,QCS 为 0)
客户端 324(已传输 0 字节,QCS 为 0)
看到“324(0 字节传输,QCS 为 0)”?套接字 324 已关闭。为什么它在析构函数的消息“Client 324 deleted”之后发生?
【问题讨论】: