完成端口GetQueuedCompletionStatus返回值的问题

先看看GetQueuedCompletionStatus函数的完整声明:
BOOL GetQueuedCompletionStatus(
HANDLE CompletionPort,      
LPDWORD lpNumberOfBytes,   
PULONG_PTR lpCompletionKey,
LPOVERLAPPED *lpOverlapped,
DWORD dwMilliseconds
);

再看看MSDN上对其返回值的说明:

If the function dequeues a completion packet for a successful I/O
operation from the completion port, the return value is nonzero. The
function stores information in the variables pointed to by the
lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped
parameters.
如果函数从完成端口取出一个成功I/O操作的完成包,返回值为非0。函数在指向lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped的参数中存储相关信息。

If *lpOverlapped is NULL and the function does not dequeue a
completion packet from the completion port, the return value is zero.
The function does not store information in the variables pointed to by
the lpNumberOfBytesTransferred and lpCompletionKey parameters. To get
extended error information, call GetLastError. If the function did not
dequeue a completion packet because the wait timed out, GetLastError
returns WAIT_TIMEOUT.
如果
*lpOverlapped为空并且函数没有从完成端口取出完成包,返回值则为0。函数则不会在lpNumberOfBytes and
lpCompletionKey所指向的参数中存储信息。调用GetLastError可以得到一个扩展错误信息。如果函数由于等待超时而未能出列完成
包,GetLastError返回WAIT_TIMEOUT.

If *lpOverlapped is not NULL and the function dequeues a completion
packet for a failed I/O operation from the completion port, the return
value is zero. The function stores information in the variables pointed
to by lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped. To
get extended error information, call GetLastError
如果
*lpOverlapped不为空并且函数从完成端口出列一个失败I/O操作的完成包,返回值为0。函数在指向
lpNumberOfBytesTransferred, lpCompletionKey, and
lpOverlapped的参数指针中存储相关信息。调用GetLastError可以得到扩展错误信息

If a socket handle associated with a completion port is closed,
GetQueuedCompletionStatus returns ERROR_SUCCESS, with lpNumberOfBytes
equal zero.
如果关联到一个完成端口的一个socket句柄被关闭了,则GetQueuedCompletionStatus返回ERROR_SUCCESS,并且lpNumberOfBytes等于0

相应的,我处理的方式:
while(){

flag=GetQueuedCompletionStatus(
HANDLE CompletionPort,      
LPDWORD lpNumberOfBytes,   
PULONG_PTR lpCompletionKey,
LPOVERLAPPED *lpOverlapped,
DWORD dwMilliseconds
);

针对:如果 *lpOverlapped为空并且函数没有从完成端口取出完成包,返回值则为0。函数则不会在lpNumberOfBytes and lpCompletionKey所指向的参数中存储信息。

if(lpOverlapped== NULL) {continue;}

针对: 如果
*lpOverlapped不为空并且函数从完成端口出列一个失败I/O操作的完成包,返回值为0。函数在指向
lpNumberOfBytesTransferred, lpCompletionKey, and
lpOverlapped的参数指针中存储相关信息。调用GetLastError可以得到扩展错误信息
if(FALSE == flag && GetLastError()!=0){ 归还IO句柄;continue;}

针对:如果关联到一个完成端口的一个socket句柄被关闭了,则GetQueuedCompletionStatus返回ERROR_SUCCESS,并且lpNumberOfBytes等于0 .

ERROR_SUCCESS这个值是0,即返回值是0(false)且GetLastError()等于0,与上面的错误处理代码是有分别的。
if(opType != IO_ACCEPT && dwByteTrans == 0) {做断开处理,归还IO;continue;}

针对: 如果函数从完成端口取出一个成功I/O操作的完成包,返回值为非0。函数在指向lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped的参数中存储相关信息。
switch(){根据IO类型做相关操作}

}

现在的问题是:我需要在(FALSE == flag &&
GetLastError()!=0)的情况下做一些处理。导致GetQueuedCompletionStatus返回失败的因素有很多,最常见的是
〖1236〗-由本地系统终止网络连接,〖1234〗-没有任何服务正在远程系统上的目标网络终结点上操作,〖64〗-指定的网络名不再可用等等。之前发
生错误时简单的回还IO句柄,但有些问题由此而产生。

1.WSASEND/WSARECV调用成功,但实际上IO被重置,GetQueuedCompletionStatus返回错误。

2.服务器主动关闭了socket,导致投递的io返回。
3.由其他原因导致io失败等。如udp等待接收的socket会发生997错误:重叠 I/O 操作在进行中。(这个也不好理解,为什么接收在进行却返回?应该阻塞等待其完成返回啊)

之前没想到udp等待接收的IO会失败返回,于是未加区分的归还IO了事。(面向终端的tcp的io请求失败后,由于终端重连时会继续投递接收请
求,因此面向终端的一边是没有问题的)导致后期udp
socket没有接收请求投递而收不到任何数据。因此需要在这个错误处理过程中区分IO类型分别做处理。这里复杂的原因在于该完成端口绑定了tcp
socket,udp socket,等待连接的socket,主动连接的socket等等这些类型,用途各异的socket。

这样,需要在udp请求IO失败后主动的重新投递接收请求,主动地向服务器发送。在此过程中需要取完成键,一个奇怪的现象产生了,此时的完成键
lpCompletionKey有时候为NULL。按照MS的说法:如果
*lpOverlapped不为空并且函数从完成端口出列一个失败I/O操作的完成包,返回值为0。函数在指向
lpNumberOfBytesTransferred, lpCompletionKey,
lpOverlapped的参数指针中存储相关信息。如果*lpOverlapped为空,则参数不赋值。而我在前一种情况下的完成键却是NULL,并未
赋值。之前没考虑,从中取值导致程序时常崩溃,现在加入判断则恢复正常.

但是为什么完成键在IO句柄不为空的情况下没有赋值?这个问题依然不解,而且对我的系统而言仍然有隐忧。我是在完成键赋值的情况下会重新投递面向IAG的udp接收请求,若完成键没有赋值,投递io没有进行,后期的数据会收不到。这种情况虽然没有发生,但是是有可能的。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wangandy7811/archive/2009/12/03/4930885.aspx

GetQueuedCompletionStatus的返回值的更多相关文章

  1. socket读写返回值的处理

    在调用socket读写函数read(),write()时,都会有返回值.如果没有正确处理返回值,就可能引入一些问题 总结了以下几点 1当read()或者write()函数返回值大于0时,表示实际从缓冲 ...

  2. Dapper逆天入门~强类型,动态类型,多映射,多返回值,增删改查+存储过程+事物案例演示

    Dapper的牛逼就不扯蛋了,答应群友做个入门Demo的,现有园友需要,那么公开分享一下: 完整Demo:http://pan.baidu.com/s/1i3TcEzj 注 意 事 项:http:// ...

  3. 由Dapper QueryMultiple 返回数据的问题得出==》Dapper QueryMultiple并不会帮我们识别多个返回值的顺序

    异常汇总:http://www.cnblogs.com/dunitian/p/4523006.html#dapper 今天帮群友整理Dapper基础教程的时候手脚快了点,然后遇到了一个小问题,Dapp ...

  4. C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解

    前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧.之前分享过一篇 C#进阶系列——WebApi接口传参不再困惑:传参详解  ...

  5. Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值

    Asp.net中存储过程拖拽至dbml文件中,提示无法获得返回值,去属性表中设置这时候会提示你去属性表中更改返回类型. 其实存储过程返回的也是一张表,只不过有时候存储过程有点复杂或者写法不规范的话不能 ...

  6. SubSonic3.0使用存储过程查询时,不能使用output参数返回值的问题修改

    有个群友问SubSonic3.0执行存储过程时能不能使用output参数返回值,说测试过后获取不到返回值,早上有些时间所以就尝试修改了一下 首先在数据库中创建一个存储过程 CREATE PROCEDU ...

  7. 支持多返回值存储过程的SqlHelper

    public readonly string connStr = ConfigurationManager.ConnectionStrings["sql"].ConnectionS ...

  8. sql语句返回值的问题

    由于执行sql语句的时候执行成功或者失败会返回执行的影响函数,用list是因为查询的结果可能为null也可能set后放到集合里去: 所以返回值类型用int

  9. JsonResult作为Action返回值时的错误

    JsonResult作为Action返回值时的错误   System.InvalidOperationException: This request has been blocked because ...

随机推荐

  1. window+git+AndroidStudio+github

    1. 安装配置git 安装:需要从网上下载一个,然后进行默认安装即可.安装完成后,找到 “Git Bash”,点击: 配置: 注意:name和email 只是用来标识身份,但是一定要配置好 2. St ...

  2. AIX 第2章 指令记录

    root@db:/#mount  node       mounted        mounted over    vfs       date        options     ------- ...

  3. 最冤枉的关键字----sizeof

    <h4>一.常年被人误认为函数.</h4> sizeof 是关键字不是函数,其实就算不知道它是否为32 个关键字之一时,我们也可以借助编译器确定它的身份.看下面的例子: int ...

  4. 深入学习Heritrix---解析CrawlController(转)

    当我们以Web UI方式使用Heritrix时,点击任务开始(start)按钮时,Heritrix就开始了它的爬取工作.但它的内部 执行流程是怎样的呢?别急,下面将慢慢道来. (一)CrawlJobH ...

  5. RAC 环境下修改归档模式

    RAC环境下的归档模式切换与单实例稍有不同,主要是共享存储所产生的差异.在这种情况下,我们可以将RAC数据库切换到非集群状态下,仅仅在一个实例上来实施归档模式切换即可完成RAC数据库的归档模式转换问题 ...

  6. Android使用绘图Path总结

    Path作为Android中一种相对复杂的绘图方式,官方文档中的有些解释并不是很好理解,这里作一个相对全面一些的总结,供日后查看,也分享给大家,共同进步. 1.基本绘图方法 addArc(RectF ...

  7. Android总结篇——Intent机制详解及示例总结

         最近在进行android开发过程中,在将 Intent传递给调用的组件并完成组件的调用时遇到点困难,并且之前对Intent的学习也是一知半解,最近特意为此拿出一些时间,对Intent部分进行 ...

  8. Excel2007条件格式怎么用

    Excel2007的条件格式功能十分的强大实用,较2003版改进十分的大,下面我们以经验记录为例做一简单的操作示范.注意前部分有二点技巧可借鉴,即不规则选取和不规则统一填充. 工具/原料 EXCEL2 ...

  9. Oracle自定义数据类型 2 (调用对象方法)

    调用对象方法 调用对象方法基于类型创建表后,就可以在查询中调用对象方法 A. 创建基于对象的表语法: create   table   <表名>   of   <对象类型>意义 ...

  10. TextView------文字底部或者中间加横线

    promotionLinkText = (TextView) this .findViewById(R.id. text_promotion_link ); 中间加横线 promotionLinkTe ...