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

在完成例程的回调函数CALLBACK CompletionRoutine 内,如何通过回调参数 Overlapped 来判断是哪个套接字发生了IO操作?我看了几个例子,好像通常是自己定义一个结构体然后把WSAOVERLAPPDE放在第一的位置,然后在回调函数内强制转换,比如:

// 这里是定义的结构体
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,也就是所取到的值和变量的名称不是对应的了,是错乱的,估计是指针进行强制转化的时候出了问题,请问要如何操作才能像结构体那样成功转化呢?

// 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

==================================================================
问题一:
你调用一个函数,比如WSARecv,其需要的是一个WSAOVERLAPPED指针,在回调函数里,你得到的也是这个WSAOVERLAPPED指针(它们指向同一片内存),现在比如你想得到cpIP,则它就在从WSAOVERLAPPED指针开始的,sizeof(WSAOVERLAPPED)之后的位置上。而把WSAOVERLAPPED指针强转为_SOCKET_INFORMATION指针,是为了书写上的方法,直接->cpIP就取到了,不强转也是做得到的,就麻烦了,你还需要自己去在内存中移动指针。
相反,如果WSARecv需要一个WSAOVERLAPPED参数,则它就是按值传递的,那么在回调函数里,就无法通过强转得到_SOCKET_INFORMATION,因为传值的时候,只传了WSAOVERLAPPED,后面的_SOCKET_INFORMATION多出来的部分并没有拷贝。
这说白了就是传指针、传引用与传值的区别了,你的c++知识严重不足。

问题二:
因为你有一个~CXEDUser()虚函数,造成了类大小的改变(增加了虚表),那么CXEDUser的地址就不再与成员m_Overlapped地址重合,那么强转就是错误的。
你可以把virtual去掉,应该就可以了(但去掉析构函数的virtual并不标准,不推荐)。

建议:
从WSAOVERLAPPED继承才是最好的解决办法,比那个struct强,你自己慢慢领会:
class CXEDUser : public WSAOVERLAPPED
{
public:
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* user = new(…);
WSARecv(…, user);

回调时:
CXEDUser* user = (CXEDUser*) par;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值