重叠I/O里数据包的封装格式及接收顺序问题 本帖最后由 passswords 于 2009-06-10 14:26:14 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 楼上说的没错,对于同一个SOCKET的传输来的数据是不能异步的,异步只是在不同SOCKET之间才能实现 lz分3次recv一个完整的包吗?服务端(发送端)是如何send的呢?用异步出现接收时包顺序改变的话,可以在自己的这边把包顺序强行改正过来,比如:用指针指向这3个数据包,等全部接收完成,再调整顺序。 楼上说不能多次recv的,看来是我没把问题说清楚。整个过程是这样的:原先使用的是基于消息的I/O,不是重叠的I/O;所以用分段截取数据流的方法可以很好的各取所需。当触发了FD_RECEIVE事件,调用其响应函数,在该函数中//处理前先注销FD_READ事件if(!AsyncSelect(0)){ TRACE0(...); retrun;}//recv的时候先Receive(&wPackType,sizeof(wPackTYpe),0)接收数据包类型 WORD wPackType;if(Receive(&WORD wPackType;,sizeof(WORD wPackType;),0)!=sizeof()){ TRACE0(...);}//然后分析数据包类型并调用相应的处理函数 switch(wPackType) { case PACKAGE_USERLIST: OnReceiveUserList();break; case ... . . } //在 OnReceiveUserList里,先读取列表长度 Recevice((void*)&len,sizeof(len),0) //再根据长度,读取完剩下的数据,//处理完毕,重新注册网络事件if(AsyncSelect(FA_READ|FD_CLOSE){TRACE0(..);retrun;}但是对于重叠的操作,这就有问题了。首先,由于我们已经准备好了应用程序的缓冲区,所以,当有数据到达的时候就直接填充应用程序缓冲区,而绕过了该套接字的系统缓冲区。接着,所有重叠操作可确保按照应用程序安排好的顺序执行,然而,不能确保从完成端口返回的完成通知也按照上述顺序执行。也就是说,对于两个重叠WSARecv操作,如果一个应用程序提供前者10KB的缓冲,而后者提供12KB的缓冲,则10KB缓冲先被填充,然后12KB缓冲被填充。应用程序的工作线程可能会在10KB操作完成事件之前从GetQueuedCompletionStatus接收到12KB WSARecv的通知,总而言之,由于顺序的不确定。,我们没法象以前那样分段截流了,我看到有些资料说,为提交的读I/O分配序列号,但我想不出该怎么实现,所以来请各位帮帮忙,有其他解决方法更好。不知道这回我把问题说清楚了没。本人表达能力有限,惭愧 -_-!! 发送的时候是一次发送,但是MTU的限制,数据可能被分成多个包。接收的时候就会分批到达。 “但是换成重叠I/O的话WSARecv的时候由于是重叠的 可能会这样收 用户个数 ,数据包类型,用户信息 也就是说,多个异步读调用的时候,我接收的顺序可能组成错误的封包,这个该怎么解决呢? 为提交的读I/O分配序列号???那又怎么分呢,怎么实现呢?大家帮帮忙呀”不会出现你说的这种情况的,除非,你在接收这3个信息时,创建了3个socket,然后分别wsarecv;如果只是一个socket的话,那么你先wsarecv哪个,结果就是先收到哪个的数据。不过一般处理时,对同一个socket,是等wsarecv后,实际接收到数据后,才再一次wsarecv,接收下一个数据包。WSAGetOverlappedResult( g_CliSocketArr[index], &g_pPerIODataArr[index]->overlap, &cbTransferred, TRUE, &g_pPerIODataArr[g_iTotalConn]->Flags);参考Windows Socket五种I/O模型——代码全攻略(一)(转)http://hi.baidu.com/xyh2007/blog/item/7f2ebf3de1e69e07bba1674e.html “应用程序的工作线程可能会在10KB操作完成事件之前从GetQueuedCompletionStatus接收到12KB WSARecv的通知,总而言之,由于顺序的不确定。,我们没法象以前那样分段截流了,我看到有些资料说,为提交的读I/O分配序列号,但我想不出该怎么实现,所以来请各位帮帮忙,有其他解决方法更好。 ”BOOL GetQueuedCompletionStatus( HANDLE CompletionPort, LPDWORD lpNumberOfBytes, PULONG_PTR lpCompletionKey, LPOVERLAPPED* lpOverlapped, DWORD dwMilliseconds);这个函数的第四个参数可以指明2次wsarecv的不同,所以如果你所说的12kb的先到达的话,那么也是可以区分的。把这12kb的数据放到你需要放到缓冲区就可以了啊~ 但是对于重叠的操作,这就有问题了。首先,由于我们已经准备好了应用程序的缓冲区,所以,当有数据到达的时候就直接填充应用程序缓冲区,而绕过了该套接字的系统缓冲区。 接着,所有重叠操作可确保按照应用程序安排好的顺序执行,然而,不能确保从完成端口返回的完成通知也按照上述顺序执行。也就是说,对于两个重叠WSARecv操作,如果一个应用程序提供前者10KB的缓冲,而后者提供12KB的缓冲,则10KB缓冲先被填充,然后12KB缓冲被填充。应用程序的工作线程可能会在10KB操作完成事件之前从GetQueuedCompletionStatus接收到12KB WSARecv的通知,总而言之,由于顺序的不确定。,我们没法象以前那样分段截流了,我看到有些资料说,为提交的读I/O分配序列号,但我想不出该怎么实现,所以来请各位帮帮忙,有其他解决方法更好。 发送数据的时候,加一个计数段位,就算后12KB先触发,你先在内存缓存,等到相应的数据全接受完了,自己重组。这样之后再进行你的后续操作。 对于同一个socket通知也是按顺序的 我算弄明白了,打个比方:封装数据包结构:数据包类型+用户个数+用户信息,当数据发过来以后,这些数据存放到一个缓冲区A里面了。当你的Thread1在用WSARecv读数据的时候,从A里面读取数据,假设读入了数据包类型后,这个时候Thread2也读入数据,那个这个Thread2读入的数据必然是用户个数,而不是用户信息。因为数据包都在A里面,并且当线程读入了数据以后,相应的数据将从A里面删除。你可以把WSARecv想象成原子操作。所以,不会这样收到“用户个数 ,数据包类型,用户信息”这样的数据。 MFC触发信号问题 关于三叉切分窗口的问题。 来者有分,如何得取BITMAPINFOHEADER 关于VC调用javascript的方法,请指点一下。 请教:请各位大哥帮我看看下面几个类的问题,谢谢! 哪儿有VC6.0的最新补丁下载呢 CFILE 读取图片为啥显示不出来内容? 求助:CListCtrl分组header的背景如何自绘 如何读AVI文件到缓冲区 关于在View中的刷新操作 sdk中的视图滚动的问题 寻求 好友目录树和皮肤 解决方案
lz分3次recv一个完整的包吗?
服务端(发送端)是如何send的呢?用异步出现接收时包顺序改变的话,可以在自己的这边把包顺序强行改正过来,比如:用指针指向这3个数据包,等全部接收完成,再调整顺序。
if(!AsyncSelect(0))
{ TRACE0(...);
retrun;
}//recv的时候先Receive(&wPackType,sizeof(wPackTYpe),0)接收数据包类型
WORD wPackType;
if(Receive(&WORD wPackType;,sizeof(WORD wPackType;),0)!=sizeof())
{ TRACE0(...);
}//然后分析数据包类型并调用相应的处理函数
switch(wPackType)
{
case PACKAGE_USERLIST: OnReceiveUserList();break;
case ...
. .
} //在 OnReceiveUserList里,先读取列表长度
Recevice((void*)&len,sizeof(len),0)
//再根据长度,读取完剩下的数据,//处理完毕,重新注册网络事件
if(AsyncSelect(FA_READ|FD_CLOSE)
{
TRACE0(..);
retrun;
}但是对于重叠的操作,这就有问题了。首先,由于我们已经准备好了应用程序的缓冲区,所以,当有数据到达的时候就直接填充应用程序缓冲区,而绕过了该套接字的系统缓冲区。
接着,所有重叠操作可确保按照应用程序安排好的顺序执行,然而,不能确保从完成端口返回的完成通知也按照上述顺序执行。也就是说,对于两个重叠WSARecv操作,如果一个应用程序提供前者10KB的缓冲,而后者提供12KB的缓冲,则10KB缓冲先被填充,然后12KB缓冲被填充。应用程序的工作线程可能会在10KB操作完成事件之前从GetQueuedCompletionStatus接收到12KB WSARecv的通知,总而言之,由于顺序的不确定。,我们没法象以前那样分段截流了,我看到有些资料说,为提交的读I/O分配序列号,但我想不出该怎么实现,所以来请各位帮帮忙,有其他解决方法更好。不知道这回我把问题说清楚了没。本人表达能力有限,惭愧 -_-!!
发送的时候是一次发送,但是MTU的限制,数据可能被分成多个包。接收的时候就会分批到达。
可能会这样收
用户个数 ,数据包类型,用户信息
也就是说,多个异步读调用的时候,我接收的顺序可能组成错误的封包,这个该怎么解决呢? 为提交的读I/O分配序列号???那又怎么分呢,怎么实现呢?大家帮帮忙呀”不会出现你说的这种情况的,除非,你在接收这3个信息时,创建了3个socket,然后分别wsarecv;如果只是一个socket的话,那么你先wsarecv哪个,结果就是先收到哪个的数据。
不过一般处理时,对同一个socket,是等wsarecv后,实际接收到数据后,才再一次wsarecv,接收下一个数据包。
WSAGetOverlappedResult(
g_CliSocketArr[index],
&g_pPerIODataArr[index]->overlap,
&cbTransferred,
TRUE,
&g_pPerIODataArr[g_iTotalConn]->Flags);
参考
Windows Socket五种I/O模型——代码全攻略(一)(转)
http://hi.baidu.com/xyh2007/blog/item/7f2ebf3de1e69e07bba1674e.html
”
BOOL GetQueuedCompletionStatus(
HANDLE CompletionPort,
LPDWORD lpNumberOfBytes,
PULONG_PTR lpCompletionKey,
LPOVERLAPPED* lpOverlapped,
DWORD dwMilliseconds
);
这个函数的第四个参数可以指明2次wsarecv的不同,所以如果你所说的12kb的先到达的话,那么也是可以区分的。把这12kb的数据放到你需要放到缓冲区就可以了啊~
接着,所有重叠操作可确保按照应用程序安排好的顺序执行,然而,不能确保从完成端口返回的完成通知也按照上述顺序执行。也就是说,对于两个重叠WSARecv操作,如果一个应用程序提供前者10KB的缓冲,而后者提供12KB的缓冲,则10KB缓冲先被填充,然后12KB缓冲被填充。应用程序的工作线程可能会在10KB操作完成事件之前从GetQueuedCompletionStatus接收到12KB WSARecv的通知,总而言之,由于顺序的不确定。,我们没法象以前那样分段截流了,我看到有些资料说,为提交的读I/O分配序列号,但我想不出该怎么实现,所以来请各位帮帮忙,有其他解决方法更好。
发送数据的时候,加一个计数段位,就算后12KB先触发,你先在内存缓存,等到相应的数据全接受完了,自己重组。
这样之后再进行你的后续操作。
封装数据包结构:数据包类型+用户个数+用户信息,当数据发过来以后,这些数据存放到一个缓冲区A里面了。当你的Thread1在用WSARecv读数据的时候,从A里面读取数据,假设读入了数据包类型后,这个时候Thread2也读入数据,那个这个Thread2读入的数据必然是用户个数,而不是用户信息。因为数据包都在A里面,并且当线程读入了数据以后,相应的数据将从A里面删除。你可以把WSARecv想象成原子操作。所以,不会这样收到“用户个数 ,数据包类型,用户信息”这样的数据。