1) 即使ReadFile或者WriteFile函数返回真,完成包还是会从GetQueuedCompletionStatus取得。
2) 与完成端口句柄绑定的套接字,其设置超时选项虽然可以成功,却是无效的。因为其相当于非阻塞模式,超时只是对阻塞模式而言的。
3) 一旦相关的套接字操作发生网络错误,GetQueuedCompletionStatus会返回假。通过GetQueuedCompletionStatus返回的lpOverlapped值来判断,如果此值返回空,则说明不是与套接字相关网络错误,而是GetQueuedCompletionStatus本身产生的错误,最常用的是WAIT_TIMEOUT错误,(即通过设置此函数的超时,产生的错误)可以在函数返回的线程调用GetLastError函数获取错误码。
4) 要从完成端口里取消已经提交的I/O操作,可以直接关闭这个套接字,则就会导致发生网络错误(依照第3条),错误是ERROR_NETNAME_DELETED。
5) 一次I/O操作,只要调用成功(ReadFile或WriteFile返回真,或者返回假但错误是“I/O未决Pending”),就一定会有一个完成包可以从GetQueuedCompletionStatus获取出来。
6)虽然可以多次对一个套接字连续多次调用ReadFile或WriteFile(即使前一次是未决,下一次也可以成功,也就是说完成端口允许这样的行为),但从逻辑上说,很难保证数据的正确性。所以,一般要保证同一时间点上最多有一个ReadFile和WriteFile是未决操作。
7)关于第4条,其实存在一个使用CancelIoEx的可能性,但是,要保持状态一致性,一般要对套接字加锁,降低整体效率,仔细权衡的结果是使用closesockct,不是使用CancelIoEx。
8)要设计操作完成端口的中间件主要需要解决“何时删除对象”的时机问题,则一个直观的方案是用引用计数和状态跳转法。
下面是操作引用计数和状态跳转的联合体,其中域refs是引用计数,normal标志socket状态,1为开启,0为关闭。
union sio_object_flag
{
struct{
u_int refs : 31;
u_int normal : 1;
};
long volatile quad;
};
typedef union sio_object_flag sio_object_flag;
2) 与完成端口句柄绑定的套接字,其设置超时选项虽然可以成功,却是无效的。因为其相当于非阻塞模式,超时只是对阻塞模式而言的。
3) 一旦相关的套接字操作发生网络错误,GetQueuedCompletionStatus会返回假。通过GetQueuedCompletionStatus返回的lpOverlapped值来判断,如果此值返回空,则说明不是与套接字相关网络错误,而是GetQueuedCompletionStatus本身产生的错误,最常用的是WAIT_TIMEOUT错误,(即通过设置此函数的超时,产生的错误)可以在函数返回的线程调用GetLastError函数获取错误码。
4) 要从完成端口里取消已经提交的I/O操作,可以直接关闭这个套接字,则就会导致发生网络错误(依照第3条),错误是ERROR_NETNAME_DELETED。
5) 一次I/O操作,只要调用成功(ReadFile或WriteFile返回真,或者返回假但错误是“I/O未决Pending”),就一定会有一个完成包可以从GetQueuedCompletionStatus获取出来。
6)虽然可以多次对一个套接字连续多次调用ReadFile或WriteFile(即使前一次是未决,下一次也可以成功,也就是说完成端口允许这样的行为),但从逻辑上说,很难保证数据的正确性。所以,一般要保证同一时间点上最多有一个ReadFile和WriteFile是未决操作。
7)关于第4条,其实存在一个使用CancelIoEx的可能性,但是,要保持状态一致性,一般要对套接字加锁,降低整体效率,仔细权衡的结果是使用closesockct,不是使用CancelIoEx。
8)要设计操作完成端口的中间件主要需要解决“何时删除对象”的时机问题,则一个直观的方案是用引用计数和状态跳转法。
下面是操作引用计数和状态跳转的联合体,其中域refs是引用计数,normal标志socket状态,1为开启,0为关闭。
union sio_object_flag
{
struct{
u_int refs : 31;
u_int normal : 1;
};
long volatile quad;
};
typedef union sio_object_flag sio_object_flag;