完成端口取消已投递的IO操作的问题

lsgt 2009-10-20 10:38:54
先描述,后代码。
先投递一个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
...全文
318 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
lsgt 2009-10-30
  • 打赏
  • 举报
回复
不行啊。ConnectEx还没连接成功,没法调用DisconnectEx。各位能不能帮我测试一下》
zealstone 2009-10-27
  • 打赏
  • 举报
回复
关闭连接不应该直接调用closesocket吧,应该调用DisconnectEx(),然后在GQCS里面处理断开事件。
lsgt 2009-10-26
  • 打赏
  • 举报
回复
我这个是客户端。但我需要发起上千个连接。GQCS写的不规范没关系,我是用来测试如何取消COnnectEx的。
zealstone 2009-10-23
  • 打赏
  • 举报
回复
帮楼主顶一下。
你这个是服务端还是客户端,怎么又有iocp又有ConnectEx。GetQueuedCompletionStatus()这个函数返回值的处理也不标准吧。依据msdn是不是应该先判断ret?
lsgt 2009-10-21
  • 打赏
  • 举报
回复
不是吧?怎么没人理呢?
结构层次及相互联系 (1)、工作线程:响应连接的IO投递返回并负责投递读请求,并将IO返回结果投递给处理线程,可设定参数决定工作线程数量; (2)、处理线程:处理线程调用回调函数将信息传递给应用层或协议栈,可设定参数决定工作处理数量; (3)、看守线程:响应Accept事件调用AcceptEx,检测连接和心跳超时 ,将信息投递给工作线程,模块仅有一个看守线程。 1. 技术要求 (1)、线程同步:Lock指令、临界段; (2)、主要Socket API:WSASend、WSARecv、AcceptEx、DisconnectEx; (3)、内存管理:连接池(句柄重用)、内存池; (4)、数据0拷贝:通过内置处理线程,上层应用可以避免自建线程池及复制数据的过程。同时提供GBuf内存分配功能,应用层获得分配地址及填充数据之后亦可直接投递给内核/驱动层; (5)、数据顺序同步:同一个连接同时只有一个处理线程响应其IO事件; (6)、IO请求投递:单投递读、多投递写; (7)、0缓冲读投递:可条件编译实现,以适用大规模连接要求。 (8)、超时机制:可设置空连接(连接不发送数据)超时时间以防止DOS攻击,也可设置心跳超时时间防止网络故障导致的现有连接成为虚连接避免耗尽系统资源。 (9)、接口技术:API、回调函数、客户句柄(客户连接句柄)。 (10)、主、被动发送:不使用HASH、MAP及LIST技术,即可提供安全可靠高效的客户连接句柄,以实现服务器端主被动发送数据功能; (11)、PerHandleData的回收不以IO投递的计数器或链表来做依据但仍能安全回收,同时尽量避免在高频的读写操作时做其他无关的操作以提高读写效率。 (12)、处理线程和工作线程有着良好分工界限,繁重的工作交给处理线程完成,工作线程工作量最大限度的减少,仅响应投递返回及读投递操作; (13)、支持AWE,模块自动识别AWE是否开启(需手动开启),“否”则使用虚拟内存机制。 2. 功能要求 (1)、多IP多端口监听,每个监听可设置不同的回调函数,以高效的区别处理数据 (2)、可设置每秒最大的连接并发量和空连接(连接不发数据)超时时间以防止DOS攻击造成的服务瘫痪、具有心跳处理(防网络异常造成的虚连接)功能 (3)、不加协议的透明传输,可适用广泛的网络通讯环境 (4)、可现实主、被动发送数据,但不会因兼顾主动发送而额外增加降低效率的工作 (5)、内置处理线程,上层应用可不必自建线程池处理数据,所有IO事件按顺序调用回调函数并可以在回调函数内直接处理数据,不必担心多线程造成的接收数据乱序的问题。 (6)、高效率的数据对应关联机制,在初次连接并根据登录数据设置每个连接对应的宿主(Owner)之后,再接收的数据即可立即获得该连接对应的宿主,而不必再做额外的查询工作,并且模块内部采用的是指针关联方式,对于长连接、主动发送的服务器系统而言是高效率的。 (7)、可兼容IPv6 3. 注意事项 因硬件环境和应用环境不同,不合理的配置会出现效率及性能上的问题,因此以下情况出现时,请务必与作者联系以确保获得更好的参数配置: (1)、连接量超过1000个的。超过的应结合具体硬件配置和网络带宽等因素综合设定运行参数。 (2)、带宽使用率超过20%的。工作线程和处理线程数量的设置也是综合考虑数据吞吐量和数据处理负载的因素来设置的,过多的线程会在调度上浪费时间,同时也应该综合考虑线程优先级别来设置工作线程和处理线程数量,两者的设置也不一定能相等。 (3)、服务器端有主动发送需求的、短连接(含网络故障造成的连接断开)出现频率高的。 压力测试工具介绍: 一、 使用G-TcpClient模块 二、 可以设定间隔时间发起大规模长、短连接 三、 可以发起密集数据包,包括即时和定时发送,1M的光纤带宽最大可以达到100K/S(单向)以上,100M本地网最大可以达到10M/S(单向)以上 四、 数据发送仅由一个独立线程但当,每点击一次Connect就创建一个线程根据当前参数发起连接。 五、 测试前提:服务器接收客户端数据后立即原样返回给客户端

4,357

社区成员

发帖
与我相关
我的任务
社区描述
通信技术相关讨论
社区管理员
  • 网络通信
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧