完成端口取消已投递的IO操作的问题
先描述,后代码。
先投递一个ConnectEx(不带数据),在PENDING时,如果在投递操作的线程里closesocket,能够立刻返回。如果在GQCS的线程里closesocket,GQCS不会返回,知道20秒之后返回,错误码121.
在ConnectEx连接上后,在GQCS里投递一个WSARecv(服务器不返回任何数据),则不论在GQCS线程或者单独线程里closesocket,GQCS都不返回。
以上情况加不加shutdown都一样。
我还试过不用closesocket,用PostQueuedCompletionStatus,GQCS是返回了,但随后用closesocket释放资源,后面GQCS还会再返回一次。
连接上之后用国SO_UPDATE_CONNECT_CONTEXT也一样。
下面是代码:
另外还有个帖子也是问这个的,解决了一起给分。
http://topic.csdn.net/u/20091019/16/524e5415-1712-4000-8157-5210fc88bcb3.html?seed=1000414584&r=60529111#r_60529111
先投递一个ConnectEx(不带数据),在PENDING时,如果在投递操作的线程里closesocket,能够立刻返回。如果在GQCS的线程里closesocket,GQCS不会返回,知道20秒之后返回,错误码121.
在ConnectEx连接上后,在GQCS里投递一个WSARecv(服务器不返回任何数据),则不论在GQCS线程或者单独线程里closesocket,GQCS都不返回。
以上情况加不加shutdown都一样。
我还试过不用closesocket,用PostQueuedCompletionStatus,GQCS是返回了,但随后用closesocket释放资源,后面GQCS还会再返回一次。
连接上之后用国SO_UPDATE_CONNECT_CONTEXT也一样。
下面是代码:
#include <winsock2.h>
#include <mswsock.h>
#include <process.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"mswsock.lib")
struct IODATA
{
OVERLAPPED ol;
DWORD op;
SOCKET s;
HANDLE hIocp;
};
int main(int argc, char* argv[])
{
int ret=0;
DWORD bytes=0;
WSADATA data={0};
static LPFN_CONNECTEX lpfnConnectEx=NULL;
int iRet=WSAStartup(0x0202,&data);
HANDLE hIocp=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
IODATA io={0};
io.s=socket(AF_INET,SOCK_STREAM,0);
io.op=FD_CONNECT;
io.hIocp=hIocp;
CreateIoCompletionPort((HANDLE)io.s,hIocp,(ULONG_PTR)&io,0);
SOCKADDR_IN lAddr,rAddr;
lAddr.sin_family=AF_INET;
lAddr.sin_port=INADDR_ANY;
DWORD dwAddr=inet_addr("172.18.12.166");
memcpy((char*)&(lAddr.sin_addr),&dwAddr,sizeof(dwAddr));
rAddr.sin_family=AF_INET;
rAddr.sin_port=htons(80);
dwAddr=inet_addr("172.19.50.5");
memcpy((char*)&(rAddr.sin_addr),&dwAddr,sizeof(dwAddr));
ret=bind(io.s,(SOCKADDR*)&lAddr,sizeof(lAddr));
if(NULL==lpfnConnectEx)
{
GUID guid=WSAID_CONNECTEX;
ret=WSAIoctl(io.s,SIO_GET_EXTENSION_FUNCTION_POINTER,&guid,sizeof(guid),&lpfnConnectEx,sizeof(lpfnConnectEx),&bytes,NULL,NULL);
}
// _beginthreadex(NULL,0,_IoHandle,&io,0,NULL);
printf("connecting...\n");
ret=lpfnConnectEx(io.s,(SOCKADDR*)&rAddr,sizeof(rAddr),NULL,0,&bytes,&io.ol);
DWORD dwTick=GetTickCount();
while(1)
{
IODATA* pio=NULL;
LPOVERLAPPED pol=NULL;
ret=GetQueuedCompletionStatus(hIocp,&bytes,(PULONG_PTR)&pio,&pol,1000);
printf("GQCS returned --- ");
if(!pio)
{
printf("GQCS timeout.closesocket[socket=%d] -%d\n",io.s,GetTickCount()-dwTick);
if(ret==0)
{
shutdown(io.s,SD_BOTH);
closesocket(io.s); }
}
else
{
if(pio->op==FD_CONNECT)
{
if(ret)
{
printf("connect OK, recving[socket=%d]...\n",pio->s);
WSABUF wb;
wb.buf=new char[4096];
wb.len=4096;
pio->op=FD_READ;
ret=WSARecv(pio->s,&wb,1,&bytes,0,&pio->ol,NULL);
continue;
}
else
{
printf("%s[%d] failed %d\n",pio->op==FD_CONNECT ? "Connect" : "Recv",pio->s,WSAGetLastError());
break;
}
}
if(pio->op=FD_READ)
{
printf("printf returned[%d]\n",bytes);
continue;
}
}
}
system("pause");
return 0;
}
另外还有个帖子也是问这个的,解决了一起给分。
http://topic.csdn.net/u/20091019/16/524e5415-1712-4000-8157-5210fc88bcb3.html?seed=1000414584&r=60529111#r_60529111
...全文
相关推荐
WinSock完成端口IO模型.pdf
在使用完成端口模型时,发送和接收请求是通过套接字句柄投递的。当I/O操作完成后,系统会将结果放入完成端口,等待线程池中的线程处理。
Swoole实现异步投递task任务案例详解
在PHP世界中,Swoole是一个高性能的异步并发框架,它可以使得PHP程序运行在多线程、异步非阻塞的模式下,极大地提升了PHP处理高并发场景的能力。其中,Swoole的task任务机制是其核心特性之
IOCP详细理解
首先,IOCP机制中存在三个数据结构:投递队列、完成队列和闲线程队列。投递队列用于存放各种I/O操作,完成队列用于存放已经完成的I/O操作,而闲线程队列用于存放闲置的线程。
SOCKET模型之重叠IO
### SOCKET模型之重叠IO深度解析#### 一、重叠模型的优点重叠I/O模型,作为SOCKET编程中的高级技术,具有显著优势,尤其在高性能网络应用中展现出色性能。1.
代码客:G-Socket(IOCP) 1.0 (Server/Client)例程源码+Server体验程序+强大的压力测试工具
结构层次及相互联系(1)、工作线程:响应连接的IO投递返回并负责投递读请求,并将IO返回结果投递给处理线程,可设定参数决定工作线程数量;(2)、处理线程:处理线程调用回调函数将信息传递给应用层或协议栈


