如果回答客户端不能同时投递2个WSAsend,也是有问题的!
原因1、客户端的TCO可以将多个小数据包组合为一个发送
2、如果客户端的发送缓冲区大于服务器端的接收缓冲区,客户端的一个WSASend,服务器端仍要多次接收才行,仍然可能出现多个线程同时收到一个socket的数据,之后,乱序就极可能发生
原因1、客户端的TCO可以将多个小数据包组合为一个发送
2、如果客户端的发送缓冲区大于服务器端的接收缓冲区,客户端的一个WSASend,服务器端仍要多次接收才行,仍然可能出现多个线程同时收到一个socket的数据,之后,乱序就极可能发生
解决方案 »
- VC++6.0开发工具的用法
- 枚举CRichEditCtrl中的Ole对象
- 求教!编写Office插件时,LoadBehavior值会被改变成2
- 为何运行NetMeeting后就会使DirectDraw无法支持硬件加速?
- 这两天公司的宽带用BT下载突然变慢了,是不是电信把BT的端口封了?以前6、7百K的速度现在只有30K,在网上找了好多贴子都是以前的方法,我
- 关于程序在内存中的起始位置的问题,希望高手能够澄清一下概念。
- 怎么添加记录,我这个程序错在哪啊?在线等
- 程序运行后菜单项不可选,用鼠标点一下view才可选
- 不同电脑运行同一个录音程序, 结果相差很大. 是声卡的原因还是程序的原因?
- 窗口风格的问题!!!
- 右键可以转到定义,但是编译时报错,提示未声明标识符
- [新人第一贴]发送ICMP, 第一次调用recvfrom接到的是本机发的请求数据, 再次调用才能接到应答包
原因1、客户端的TCP可以将多个小数据包组合为一个发送
2、如果客户端的发送缓冲区大于服务器端的接收缓冲区,客户端的一个WSASend,服务器端仍要多次接收才行,仍然可能出现多个线程同时收到一个socket的数据,之后,乱序就极可能发生
3、即便是一个小的数据包,发送端和服务器端都可能分次发送与接收,
我的问题是:多个服务器端线程,同时收到同一个socket发来的数据,在写入缓冲区的时候,如何保证不乱序(线程切换时随机的,不能100%保证先收到的数据先写入缓冲区)?
虽然使用 I/O 完成端口的操作总会按照它们被提交的顺序完成,但是线程调度问题可能
会导致关联到完成端口的实际工作不按正常循序完成。例如,有两个I/O 工作线程,应该接
收“字节块1,字节块2,字节块3”,但是你可能以错误顺序接收到了这3 个字节块:“字节
块2,字节块1,字节块3”。这也意味着通过在完成端口上投递发送请求发送数据时,数据
实际会以错误的方式被发送。
这个问题可以通过仅使用一个工作线程,仅提交一个I/O 调用,然后等待它完成来避免。
但是这样就失去了IOCP 的所有优点。
此问题的一个简单的解决方法是向提交的缓冲区对象中添加序列号,如果缓冲区序列号
是连续的,就处理缓冲区中的数据。这意味着,有着错误序号的缓冲区要被保存下来,以便
今后使用。
另外,大多数网络协议都是基于封包的,这里,开始的X 个字节描述协议头,协议头包
含的信息说明了整个封包到底有多大。服务器可以读协议头,计算出还需要读多少数据,然
后继续读后面的数据,直到得到完整的封包。当服务器一次仅做一个异步读调用时,这工作
得很好。但是,如果想要发挥IOCP 服务器全部潜力,就应该有多个未决的异步读操作等待
数据的到来。这意味着,多个异步读操作不按顺序完成,未决读I/O 返回的字节流不能按顺
序处理,接收到的字节流可能组合成正确的封包,也可能组合成错误的封包。所以,必须要
为提交的读I/O 分配序列号。
虽然使用 I/O 完成端口的操作总会按照它们被提交的顺序完成,但是线程调度问题可能
会导致关联到完成端口的实际工作不按正常循序完成。例如,有两个I/O 工作线程,应该接
收“字节块1,字节块2,字节块3”,但是你可能以错误顺序接收到了这3 个字节块:“字节
块2,字节块1,字节块3”。这也意味着通过在完成端口上投递发送请求发送数据时,数据
实际会以错误的方式被发送。
这个问题可以通过仅使用一个工作线程,仅提交一个I/O 调用,然后等待它完成来避免。
但是这样就失去了IOCP 的所有优点。
此问题的一个简单的解决方法是向提交的缓冲区对象中添加序列号,如果缓冲区序列号
是连续的,就处理缓冲区中的数据。这意味着,有着错误序号的缓冲区要被保存下来,以便
今后使用。
另外,大多数网络协议都是基于封包的,这里,开始的X 个字节描述协议头,协议头包
含的信息说明了整个封包到底有多大。服务器可以读协议头,计算出还需要读多少数据,然
后继续读后面的数据,直到得到完整的封包。当服务器一次仅做一个异步读调用时,这工作
得很好。但是,如果想要发挥IOCP 服务器全部潜力,就应该有多个未决的异步读操作等待
数据的到来。这意味着,多个异步读操作不按顺序完成,未决读I/O 返回的字节流不能按顺
序处理,接收到的字节流可能组合成正确的封包,也可能组合成错误的封包。所以,必须要
为提交的读I/O 分配序列号。不知道这是什么书写的,不过怎可能失去所有优点,你一个服务器又不是面对一个链接,为什么要增加这种复杂性非要把同一个socket分成多个线程去操作,这不用iocp,用其他的模型出的问题是一样的。
而且上面提到的方法,我是想不出对提出的问题有任何帮助。你用几个工作线程和你一个socket只用一个线程投递一次请求不冲突。
没看懂你的问题。1. 不说线程。说异步既然是异步,那么也是无法保证顺序的。需要自己搞。工作线程不断的getqueuecompletionstatus ,分析数据,然后继续投递。完全有可能同一个线程对 同一个套接字投递。即使不存在 同时投递,那么 也有问题要考虑:线程1 ,线程2 都接受 同一个客户端的数据, 你说这种可能性有没有?所以必须对数据编号。
在C处理数据的时候,客户B的数据到了,于是,Get收到1800字节B的数据,通知D线程处理,此时,C线程处理完了(投递Recv后,空闲),此时Get收到B的剩余1200字节,只能由C处理,
这时候,C,D 2线程同时操作客户B数据,由于线程切换的随机,有可能D线程仅将800字节写入缓冲后,被切换,此时C线程执行,将1200字节写入缓冲,之后D线程获得时间片,再将剩余的1000字节写入缓冲,于是乱序出现了,实际上这种情况也不乱序,我不知道为什么不会乱序?
----------------------------
IOCP哪里规定了必须使用同一个线程接收一个socket的数据?
是一次一个socket只能投递一个recv 不管你多少个工作线程 这样怎么会乱序?你一个socket投递2个recv那当然可能乱序...
--------------------------------------------------------------------------------------我说的你没理解:
你说的:
一个socket只能投递一个recv
我问你:
假设客户端要发送1234567890,由于网络很卡,发送方发送了2次,假设服务器也很卡,数据分3次才收完,那么在第一次和第二次收完后(假设收到1234567),getqueuecompletionstatus不返回?服务器端一定要收到全部的1234567890才返回?如果是这样,原因是什么?
你的如果不成立 你提交的recv100字节的操作 系统只会尽可能的多收数据满足你recv1000字节的要求只来了500 getqueuecompletionstatus肯定会返回告诉你只收到500数据...
------------------------------------------------------------------------
是不是应该为:你提交的recv1000字节的操作
当然会有收到部分的情况 这种情况要看你自己定义的协议是什么 如果发送端会保证需要发多少就一定能发多少 那你接收端只要不停recv就是了 事实上大部分的网络编程 recv的操作都是不停的recv 将recv的数据放到缓冲区或者只直接就开始解析...
当然会有收到部分的情况 这种情况要看你自己定义的协议是什么 如果发送端会保证需要发多少就一定能发多少 那你接收端只要不停recv就是了 事实上大部分的网络编程 recv的操作都是不停的recv 将recv的数据放到缓冲区或者只直接就开始解析...-----------------------------------------------------
照你的说法,我请教一下:
如果服务器收到了500字节,此时客户端是不是已经发生了1000字节?
当然会有收到部分的情况 这种情况要看你自己定义的协议是什么 如果发送端会保证需要发多少就一定能发多少 那你接收端只要不停recv就是了 事实上大部分的网络编程 recv的操作都是不停的recv 将recv的数据放到缓冲区或者只直接就开始解析...-----------------------------------------------------
照你的说法,我请教一下:
如果服务器收到了500字节,此时客户端是不是已经发生了1000字节?客户端有没有发1000字节 这个客户端那里检测不到么? 只要客户端保证发送了1000字节 只要socket没有断你的服务器recv逻辑在getqueuecompletionstatus告诉你只收到500字节后你只要保存好这500字节 再投递个recv500就是了肯定会收到剩下的500字节要是getqueuecompletionstatus又返回个300你还是只要保存好这300加上前面的500 你再投递个recv200 只要保证socket没有断(TCP是保证不会丢包的) 你就一定能收到客户端发的这1000字节 你自己只要保证永远只有一个recv请求操作提交给iocp 就不存在你说的乱序...
你没有投递recv的动作 getqueuecompletionstatus当然不返回 数据只是存在网卡而已 要是你一直不接收客户端还一直send最后的结果就是 客户端send会失败 getlasterror 就是缓冲区不够...
是每个socket都有自己的缓冲区 你这个链接不接收不影响其他的链接 一直不接收只会让你这个链接的远端send失败...
-----------------------------
这个是必须的
是每个socket都有自己的缓冲区 你这个链接不接收不影响其他的链接 一直不接收只会让你这个链接的远端send失败...
----------------------------------------------------------
getqueuecompletionstatus不是一个队列吗?前面的不出列,后面的如何出去?
这个能保证怎么会乱序? 正常的处理都是在getqueuecompletionstatus返回的时候解析数据或者保存数据然后才投递下一个recv(所以哪个线程去收数据都不影响业务) 根本就不存在2个线程同时收同一个socket的数据的情况...
是每个socket都有自己的缓冲区 你这个链接不接收不影响其他的链接 一直不接收只会让你这个链接的远端send失败...
----------------------------------------------------------
getqueuecompletionstatus不是一个队列吗?前面的不出列,后面的如何出去?那你意思是一个recv投递了 客户端不发数据 iocp就堵死了是吗?? 你是这样理解iocp的?
难道getqueuecompletionstatus不是队列,是个类似Vector的结构?
什么是半包? 求解释
为什么要把简单问题复杂化呢。还是没想明白你为什么非要“两个线程”“同时”对一个socket投递。
一个完成任务的队列 只要有完成的任务 将等待的一个工作者线程唤醒 getqueuecompletionstatus返回这个任务就行了 不知道你的问题是什么...
发你的 iocp代码 ,我看看, 我是解决乱序是参考一本书上的思路,
另外:一般工作线程有2个, 线程代码是一样的, 我觉得楼主有些昏了, 楼主看这里: // 关联新连接到完成端口对象
::CreateIoCompletionPort((HANDLE)pClient->s, m_hCompletion, (DWORD)pClient, 0);
再看这里: BOOL bOK = ::GetQueuedCompletionStatus(pThis->m_hCompletion,
&dwTrans, (LPDWORD)&dwKey, (LPOVERLAPPED*)&lpol, WSA_INFINITE);这的socket等per-hanlde 信息是 对应的。 每一个socket 可以多次投递io请求。至于 会不会 多个线程同时投递io请求, 拙见: 不可能。 io等函数 只能被同一个线程调用吧,数据取出,或者投递后,其他线程 不会再处理了。高手斧正
我看你是把那些请求都当成系统会去线性处理了 一个一个任务顺序处理下去 你是这样理解的吧? 所以你就想不通某个任务没完成其他任务也就收不到完成了 你理解错了 你所有的请求甚至都可以同时进行 getqueuecompletionstatus只是让系统把你请求的任务结果告诉你 有就返回没有就等待...
发你的 iocp代码 ,我看看, 我是解决乱序是参考一本书上的思路,
另外:一般工作线程有2个, 线程代码是一样的, 我觉得楼主有些昏了, 楼主看这里: // 关联新连接到完成端口对象
::CreateIoCompletionPort((HANDLE)pClient->s, m_hCompletion, (DWORD)pClient, 0);
再看这里: BOOL bOK = ::GetQueuedCompletionStatus(pThis->m_hCompletion,
&dwTrans, (LPDWORD)&dwKey, (LPOVERLAPPED*)&lpol, WSA_INFINITE);这的socket等per-hanlde 信息是 对应的。 每一个socket 可以多次投递io请求。至于 会不会 多个线程同时投递io请求, 拙见: 不可能。 io等函数 只能被同一个线程调用吧,数据取出,或者投递后,其他线程 不会再处理了。高手斧正老实说只要你保证只会有一个recv操作 真的没什么乱序的问题(前提是tcp) 也就不存在你说的解决乱序一说...
对每个socket只投递一个recv,不同的socker可以同时投递
recv先接受1个包头,含有信息长度,如果recv收的字节不够,投递1个recv
如果收完整了,可以就地处理或用队列转发到其他工作线程。再投递下1个recv
这样一个客户端的包顺序是有保障的。对1个socket同时投递多个recv的,我只能表示膜拜。
单个数据包太大了,建议小于一般的MTU值乱序的问题暂时未发现,跟IOCP没多大关系~~建议你把封包里加上包序,单个包1024左右即可~~
发你的 iocp代码 ,我看看, 我是解决乱序是参考一本书上的思路,
另外:一般工作线程有2个, 线程代码是一样的, 我觉得楼主有些昏了, 楼主看这里: // 关联新连接到完成端口对象
::CreateIoCompletionPort((HANDLE)pClient->s, m_hCompletion, (DWORD)pClient, 0);
再看这里: BOOL bOK = ::GetQueuedCompletionStatus(pThis->m_hCompletion,
&dwTrans, (LPDWORD)&dwKey, (LPOVERLAPPED*)&lpol, WSA_INFINITE);这的socket等per-hanlde 信息是 对应的。 每一个socket 可以多次投递io请求。至于 会不会 多个线程同时投递io请求, 拙见: 不可能。 io等函数 只能被同一个线程调用吧,数据取出,或者投递后,其他线程 不会再处理了。高手斧正老实说只要你保证只会有一个recv操作 真的没什么乱序的问题(前提是tcp) 也就不存在你说的解决乱序一说...
如何保证?接受数据与否,不是用recv函数,亲,而是用getqueuecompletionstatus函数的,难道对该函数加锁不成?只需要对其加锁乎?
发你的代码我看看,可以不?看你是如何处理的, 最好是上传整个可以使用的工程,多谢
去网上找 网络编程(第二版)附补充材料(源代码)
里面有个iocp服务器的源码,可以参考。
发你的 iocp代码 ,我看看, 我是解决乱序是参考一本书上的思路,
另外:一般工作线程有2个, 线程代码是一样的, 我觉得楼主有些昏了, 楼主看这里: // 关联新连接到完成端口对象
::CreateIoCompletionPort((HANDLE)pClient->s, m_hCompletion, (DWORD)pClient, 0);
再看这里: BOOL bOK = ::GetQueuedCompletionStatus(pThis->m_hCompletion,
&dwTrans, (LPDWORD)&dwKey, (LPOVERLAPPED*)&lpol, WSA_INFINITE);这的socket等per-hanlde 信息是 对应的。 每一个socket 可以多次投递io请求。至于 会不会 多个线程同时投递io请求, 拙见: 不可能。 io等函数 只能被同一个线程调用吧,数据取出,或者投递后,其他线程 不会再处理了。高手斧正老实说只要你保证只会有一个recv操作 真的没什么乱序的问题(前提是tcp) 也就不存在你说的解决乱序一说...
如何保证?接受数据与否,不是用recv函数,亲,而是用getqueuecompletionstatus函数的,难道对该函数加锁不成?只需要对其加锁乎? 我要是不投递异步WSARecv 你getqueuecompletionstatus就等着吧...
发你的 iocp代码 ,我看看, 我是解决乱序是参考一本书上的思路,
另外:一般工作线程有2个, 线程代码是一样的, 我觉得楼主有些昏了, 楼主看这里: // 关联新连接到完成端口对象
::CreateIoCompletionPort((HANDLE)pClient->s, m_hCompletion, (DWORD)pClient, 0);
再看这里: BOOL bOK = ::GetQueuedCompletionStatus(pThis->m_hCompletion,
&dwTrans, (LPDWORD)&dwKey, (LPOVERLAPPED*)&lpol, WSA_INFINITE);这的socket等per-hanlde 信息是 对应的。 每一个socket 可以多次投递io请求。至于 会不会 多个线程同时投递io请求, 拙见: 不可能。 io等函数 只能被同一个线程调用吧,数据取出,或者投递后,其他线程 不会再处理了。高手斧正老实说只要你保证只会有一个recv操作 真的没什么乱序的问题(前提是tcp) 也就不存在你说的解决乱序一说...
如何保证?接受数据与否,不是用recv函数,亲,而是用getqueuecompletionstatus函数的,难道对该函数加锁不成?只需要对其加锁乎? 我要是不投递异步WSARecv 你getqueuecompletionstatus就等着吧...你不会以为只要数据来了 不管你有没投递WSARecv getqueuecompletionstatus都会返回?