关于重叠IO(overlapped)模型中完成例程使用的两点疑问

问题1:在完成例程的回调函数CALLBACK CompletionRoutine 内,如何通过回调参数 Overlapped 来判断是哪个套接字发生了IO操作?我看了几个例子,好像通常是自己定义一个结构体然后把WSAOVERLAPPDE放在第一的位置,然后在回调函数内强制转换,比如:
C/C++ code
// 这里是定义的结构体typedef struct _SOCKET_INFORMATION
{
WSAOVERLAPPED Overlapped; // 重叠结构 完成例程中此结构一定要放在最前面 CHAR cpIP[16];
CHAR Buffer[DATA_BUFSIZE];
WSABUF DataBuf;
SOCKET s;
}SOCKET_INFORMATION,*LPSOCKET_INFORMATION;

// CALLBACK CompletionRoutine 的第一行进行强制转换LPSOCKET_INFORMATION SI = (LPSOCKET_INFORMATION)Overlapped;

我不理解的是:为什么在回调函数内这样强制转化就能够得到是哪个套接字发生了IO操作呢?请大家帮我理解一下这里的指针操作!谢谢!

问题2:接上述问题,我是将自己定义的这个结构体换成了一个自己的用户类,CXEDUser,类里也定义了WSAOVERLAPPED结构体,而且也如结构体一样,定义了成员变量sock, flags, dwRecvBytes,等等。并且也把overlapped放到成员变量的第一位,然后用类的指针,按照结构体的方法强制转换,但是得到了一个颠倒的结果,overlapped变成了dwRecvBytes, dwRecvBytes变成了sock,也就是所取到的值和变量的名称不是对应的了,是错乱的,估计是指针进行强制转化的时候出了问题,请问要如何操作才能像结构体那样成功转化呢?

代码:
C/C++ code
// CXEDUser 类的头文件class CXEDUser
{
public:
WSAOVERLAPPED m_Overlapped;
UINT m_uPort;
LPCTSTR m_lpIPAddress;
SOCKET m_UserSock;
WSAEVENT m_Event;
WSABUF m_DataBuf;
DWORD m_dwRecvBytes, m_dwFlags;
CXEDUser(SOCKET UserSock, LPCTSTR lpIPAddress, UINT uPort);
CXEDUser();
virtual~CXEDUser();

};

// 在回调函数中的强制转化 CXEDUser* pUser = (CXEDUser*)Overlapped;
TRACE("%d\n", pUser->m_Overlapped);// 这里输出的结果变成了发生IO操作的字节数,也就是dwRecvBytes

非常感谢
知道真是的,只能把分给一个人,其实几位的回答对我都有很大的帮助!真心的感谢各位!

对于你提出的问题有点复杂
问题1: 为什么在回调函数内这样强制转化就能够得到是哪个套接字发生了IO操作呢
是这样的,在你调用WriteFileEx或者ReadFileEx时,第4个参数就是你定义的OVERLAPPED为第一个元素的结构的指针,当IO操作完成后,系统会自动调用你所定义的FileIOCompletionRoutine,并将你调用WriteFileEx时的第4个参数的传递给FileIOCompletionRoutine的第3个参数,这个过程中传递的只是指针(即结构的地址),所以你在结构后面定义多少你自己的内容,系统都会帮你传递过去,例如结构里面包含套接字消息,那么系统帮你传递过去之后,你当然就可以知道是哪个套接字发生的IO

问题2:为什么前面定义的结构可以,但转化为类就不行了
这是因为WriteFileEx或者ReadFileEx在执行重叠IO操作时,对第4个参数,它不会去理你是什么数据类型,只需要你所给出的指针所指地址的前几个数据为OVERLAPPED的结构就可以了,也就是说WriteFileEx或者ReadFileEx的第4个参数所指的地址的内容必须是以OVERLAPPED开头的数据结构。
现在再说说类的数据结构,只要你的类的内部除了定义成员变量外还包含有成员函数(包括构建函数和析构函数),那么这个类就会自动生成一个叫做虚函数表指针的一个东西,而且是放在类结构的最前面,此时即使你将OVERLAPPED的结构放在类的最前面定义,那么这个类的指针所指地址的数据结构依然是:最前面0-3字节为虚函数表指针,从第4字节开始才是你所定义成员变量的地址,这样的地址传递给WriteFileEx或者ReadFileEx时,并不符合WriteFileEx或者ReadFileEx对第4个参数的要求(以OVERLAPPED开头),因为此时是以虚函数表指针开头的,所以即使你做了强制类型转化,执行起来也是不对的.

啰啰嗦嗦这么多,不知道有没有将问题说清楚.若仍有问题,欢迎HI我,我们一起研究追问

大师留个扣扣吧~期待交流

追答

我的QQ : 874150805

温馨提示:答案为网友推荐,仅供参考
第1个回答  2012-08-09
1. 也不一定要放在第一个位置, 放在自定成员的任何位置都可以. 只是放在第一个位置计算上方便些.
因为是第一个成员, 这个成员的地址, 也就是这个结构变量的地址.
2. 你自己的类继承与OVERLAPPED结构就可以了.追问

1. 我是不理解为什么强制转化后就能得有IO操作的那个套接字。能说明一下原理吗?
2.用自己的类来继承一个结构体吗?

追答

1. 比如自己的结构为:
typedef struct _BLOCK
{
OVERLAPPED over;
SOCKET socket;
WSABUF buf;
} BLOCK_DATA, *PBLOCK_DATA;
你要理解这个结构体成员在内存的布局. 那你就明白了. 可以在调试时, 把结构体变量地址放到内存窗口中看看.

2. 类可以继承于结构的. 比如MFC库的CRect/CPoint/CSize类, 是从标准系统结构继承的.
比如使用类为: class CBlock : public OVERLAPED;

传进去时把类转为OVERLAPPED指针即可. 收到时也转为CBlock类指针.

本回答被网友采纳
第2个回答  2012-08-09
字节数一样转换是最好的,字节数不等转换就会有问题
CXEDUser和Overlapped的数据成员都不一样,你转换我都不知道变成什么了

相关了解……

你可能感兴趣的内容

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 非常风气网