社区
网络编程
帖子详情
IOCP 多线程 接收 问题
songtao_01
2009-05-13 05:11:23
问个问题,用iocp,多线程模式下接受的时候会乱序吗?就比如一个连接先后发了两次数据:1:abcdef 2:hijklm;
然后接受到的时候,会不会是abcklmdefhij呢?如果会,如何解决。如果不会,原因是什么?粘包好解决,就是这乱序。。。。另外这种乱序我在实验过程中没出现过,但是理论上可能会出现吧,我说的对吗?敬请帮助!
...全文
703
36
打赏
收藏
IOCP 多线程 接收 问题
问个问题,用iocp,多线程模式下接受的时候会乱序吗?就比如一个连接先后发了两次数据:1:abcdef 2:hijklm; 然后接受到的时候,会不会是abcklmdefhij呢?如果会,如何解决。如果不会,原因是什么?粘包好解决,就是这乱序。。。。另外这种乱序我在实验过程中没出现过,但是理论上可能会出现吧,我说的对吗?敬请帮助!
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
36 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
sorawa
2012-07-18
打赏
举报
回复
[Quote=引用 25 楼 的回复:]
我想请问一下,SOCKET中RecvBuf里面它开设有多大,我听说是8192最大?
也是我们现在所做的SOCKET编程的send or recv是从操作系统里面为这个SOCKET开设的BUFFER中以送或接收数据,
是这样理解吗?
[/Quote]
不是这样理解,初始化缓冲区大小需要时间,操作缓冲区也需要时间,而8192 和 4096 权衡性能和缓冲大小都是很合适的。
woshisaoge
2012-07-09
打赏
举报
回复
[Quote=引用 6 楼 的回复:]
多Thread接收也不会错的
除非你同时,向一个SOCKET 发送2个Recv请求。但是如果出现这种情况你是
应该将后一个Recv排队的等待第一个Recv完成,之后在发送Recv请求
[/Quote]
对于每个客户端连接来说,需要用队列保存吗?
jy02404957
2009-08-06
打赏
举报
回复
多线程处理IO 有必要吗?
shenyi0106
2009-06-04
打赏
举报
回复
Send---->Recv 不会乱
Send Recv
Send -------> Recv 会乱,你应该加序号,这是你应用层的问题,应该你自己处理
Send Recv
mme
2009-06-04
打赏
举报
回复
6楼说的没错,关键就是每次只投递一个recv请求
Leo_red
2009-05-27
打赏
举报
回复
你再往同一个缓存里面写,就接着刚才已经写了的位置写喽,不然从缓冲区的头开始写,不就吧刚才写的东西冲掉了?
这个和粘包处理的方法一样嘛
rularys
2009-05-27
打赏
举报
回复
假如同一时刻只有一个 recv I/O 操作在等待,不会有乱序的问题;
假如同一时刻有一个以上的 recv I/O 操作在等待,则所有正在等待的操作在数据到达时,它们的完成顺序以它们被投递时的顺序为依。两种情况均与线程无关。
情况一:
任何一个线程在处理完成的recv I/O 操作时,在处理完成之前不投递下一个recv I/O ,这能保证同一时刻只有一个 recv I/O 操作在等待。
情况二:
可能同时投递了一个以上的recv I/O,但无论如何,这个“同时”对IOCP来说还是有先后顺序的,IOCP对投递的未完成操作是以先进先出的顺序来满足完成状态的。要避免多个完成的I/O操作返回时无法确认它们的先后顺序,那么在投递I/O时,可以在与I/O关联的数据中填写该I/O的投递顺序号,这样该I/O返回时,就可以根据该顺序号来确定它的完成时间位置。与I/O关联的数据,即 通常所说的单I/O数据。
songtao_01
2009-05-27
打赏
举报
回复
[Quote=引用 28 楼 Leo_red 的回复:]
你再往同一个缓存里面写,就接着刚才已经写了的位置写喽,不然从缓冲区的头开始写,不就吧刚才写的东西冲掉了?
这个和粘包处理的方法一样嘛
[/Quote]
大佬,你又误会了,我意思说的是发过来的两个包可能穿插在一起
songtao_01
2009-05-26
打赏
举报
回复
[Quote=引用 26 楼 Leo_red 的回复:]
同意,顺序由TCP协议底层保证,你按照顺序发,就肯定按照顺序收到的。
实际应用中也不会乱序,唯一的问题是你如何操作缓冲区。
你按照abcdefg来发送,收到的顺序肯定是abcdefg。你所说的一个线程收了abcd正往缓冲区里面写,另外一个线程收了efg也往里面写,就会乱。这显然…
[/Quote]
你误会我的意思了,我的意思是abcd已经写入缓存了,然后另一个线程收到了klm,然后klm往缓存写那不是就乱了
Leo_red
2009-05-26
打赏
举报
回复
[Quote=引用 3 楼 hwsts2 的回复:]
如果你能保证 发送端发送数据是有序的,那么到达接受端缓冲区内,
数据都是有序的,不会乱序,这是TCP协议规定的
[/Quote]
同意,顺序由TCP协议底层保证,你按照顺序发,就肯定按照顺序收到的。
实际应用中也不会乱序,唯一的问题是你如何操作缓冲区。
你按照abcdefg来发送,收到的顺序肯定是abcdefg。你所说的一个线程收了abcd正往缓冲区里面写,另外一个线程收了efg也往里面写,就会乱。这显然是你对共享缓冲区的互斥没有控制啊,对这个缓冲区的操作做好互斥,肯定没有你担心的问题。
allix123
2009-05-24
打赏
举报
回复
我想请问一下,SOCKET中RecvBuf里面它开设有多大,我听说是8192最大?
也是我们现在所做的SOCKET编程的send or recv是从操作系统里面为这个SOCKET开设的BUFFER中以送或接收数据,
是这样理解吗?
songtao_01
2009-05-22
打赏
举报
回复
[Quote=引用 23 楼 hwsts2 的回复:]
在一个连见上同时投递多个请求的问题:
其实无论你投递多少个请求,在最下面也是顺序完成请求的,
一般情况下你会发现你的数据都会如你所愿的接受回来,不会存在多大问题
但是有一个种情况你是很难处理的,在Recv端同时投递A,B2个请求, Client端发送
1000字节数据,结果地层接受到 500字节的时候缓冲区满了,
这个时候,你第一个请求A会顺利的返回,但是接受到的字节是 500个,也就是你
还要继续发送请求C才能接,受到剩余的数…
[/Quote]
对,我也是觉得如果真出现这种情况的话,就不好处理了,加标示也没用
人呢,多讨论啊
我看游戏服务端代码里的好像没有处理什么乱序问题,难道真的不会乱?
hwsts2
2009-05-19
打赏
举报
回复
在一个连见上同时投递多个请求的问题:
其实无论你投递多少个请求,在最下面也是顺序完成请求的,
一般情况下你会发现你的数据都会如你所愿的接受回来,不会存在多大问题
但是有一个种情况你是很难处理的,在Recv端同时投递A,B2个请求, Client端发送
1000字节数据,结果地层接受到 500字节的时候缓冲区满了,
这个时候,你第一个请求A会顺利的返回,但是接受到的字节是 500个,也就是你
还要继续发送请求C才能接,受到剩余的数据,但是这个时候 你在发送一个请求
C的话,那么这个请求会被排在第二个请求B的后面,也就是说B会把剩余的500字
节接收回来.
还有IOCP的设计目的,是处理海量连接,而不是在单连接的数据处理效率
auly403
2009-05-19
打赏
举报
回复
[Quote=引用 16 楼 songtao_01 的回复:]
引用 15 楼 scq2099yt 的回复:
不明白为什么要多个线程里接受来自同一个端口的数据,这样能给你带来什么?
可以带来效率。
[/Quote]
持怀疑态度,
除非接收的线程你要处理很多工作,比如检验,解密,之类,
那就可以带来效率
fengge8ylf
2009-05-19
打赏
举报
回复
我不明白的是发送的时候 是不是等上一个发送成功了 再投递 还是不必理上一个发送 我看BOOST的ASIO 好像可以连续投递发送
不敢确定
fengge8ylf
2009-05-19
打赏
举报
回复
投递一次请求 等这个请求完成后再投递下一个请求 即使是多线程也不会乱序
makui
2009-05-19
打赏
举报
回复
[Quote=引用 17 楼 hu_zhi_de 的回复:]
是可以提高效率:因为不用线程收一个,再投下一个WSARECV();
CPU就调用一次就可以接收两次的数据了.
[/Quote]
我觉得你这个有两个方面的问题需要考虑:
1.第一次调用的WSARecv接收的的数据是否需要在第二次接收到的数据之前处理呢?
2.假如第一次你需要读取1024的数据,你实际读到你的数据可能大于这个值;那你第二次读取到的数据怎么处理?
按你想的,还不如把WSABuf设大一点减少调用的次数
lhsxsh
2009-05-19
打赏
举报
回复
服务线程和CUP的多少有关系。
这样才能使用CUP工作的更好
scq2099yt
2009-05-14
打赏
举报
回复
不明白为什么要多个线程里接受来自同一个端口的数据,这样能给你带来什么?
xghuzd
2009-05-14
打赏
举报
回复
是可以提高效率:因为不用线程收一个,再投下一个WSARECV();
CPU就调用一次就可以接收两次的数据了.
加载更多回复(15)
IOC
P模式,socket服务器,客户连再多也不用愁
IOC
P(I/O Completion Port,I/O完成端口)是性能最好的一种I/O模型。它是应用程序使用线程池处理异步I/O请求的一种机制。在处理多个并发的异步I/O请求时,以往的模型都是在
接收
请求是创建一个线程来应答请求。这样就有很多的线程并行地运行在系统中。而这些线程都是可运行的,Windows内核花费大量的时间在进行线程的上下文切换,并没有多少时间花在线程运行上。再加上创建新线程的开销比较大,所以造成了效率的低下......
使用
IOC
P完成端口和SOCKET封装的成熟异步TCP类
使用
IOC
P完成端口和SOCKET封装的异步TCP类。 支持客户端和服务器的常用TCP接口:绑定Bind、监听Listen、
接收
Recv、连接Conn、发送Send、关闭Close。所有接口均使用异步回调的方式处理,内部实现使用Windows下性能最高的
IOC
P完成端口网络模型,并很好地处理了
多线程
安全和同步
问题
。 线程创建和事件信号量等地方用到了MFC的类,如果项目不支持MFC,可以把这些地方替换成WindowsAPI的方式。 代码是从成熟项目中分离出来的,能达到很高的性能和网络吞吐量,并且稳定无BUG。
c++高并发商业级游戏服务器干货【客户端ue4和unity3d】
1、本课程是一个干货课程,主要讲解如何封装服务器底层,使用Tcp/ip长连接,IDE使用vs2019 c++开发以及使用c++11的一些标准,跨平台windows和linux,服务器性能高效,单服务器压力测试上万无压力,服务器框架是经历过上线产品的验证,框架简单明了,不熟悉底层封装的人,半个小时就能完全掌握服务器框架上手写业务逻辑。2、本课程是一个底层服务器框架教程,主要是教会学员在windows或linux下如何封装一个高效的,避免踩坑的商业级框架,服务器底层使用初始化即开辟内存的技术,使用内存池,服务器运行期间内存不会溢出,非常稳定,同时服务器使用自定义哈希hashContainer,在处理新的连接,新的数据,新的封包,以及解包,发包,粘包的过程,哈希容器性能非常高效,增、删、查、改永远不会随着连接人数的上升而降低性能,增、删、查、改的复杂度永远都是恒定的O(1)。3、服务器底层封装没有使用任何第三方网络库以及任何第三方插件,自由度非常的高,出了任何BUG,你都有办法去修改,查找
问题
也非常方便,在windows下使用
ioc
p,linux下使用epoll.4、讲解c++纯客户端,主要用于服务器之间通信,也就是说你想搭建多层结构的服务器,服务器与服务器之间使用socket通信。还可以使用c++客户端做压力测试,开辟
多线程
连接服务器,教程提供了压力测试,学员可以自己做压力测试服务器性能。5、赠送ue4和unity3d通信底层框架以及多人交互demo,登录,注册,玩家离开,同步主要是教会学员服务器与客户端如何交互。6、赠送c++连接mysql数据库框架demo,登录,注册,玩家离开数据持久化.7、服务器教程使用自定义通信协议,同时也支持protobuf,选择权在开发者自己手里,想用什么协议都可以,自由度高。8、服务器教程使用手动敲代码逐句讲解的方式开展教学课程。非喜勿喷,谢谢大家。9、服务器教程提供源码,大家可以在平台提供的地址下载或者联系我,服务器使用c++11部分标准,std::thread,条件变量,线程锁,智能指针等,需要学员具备一定c++知识,购买前请慎重考虑。
功能强大的
IOC
P Socket Servre模块例程源码
完成端口通讯服务器(
IOC
P Socket Server)设计 (六)功能强大的
IOC
P Socket Servre模块例程源码 Copyright © 2009 代码客(卢益贵)版权所有 QQ:48092788 源码博客:http://blog.csdn.net/guestcode 一、声明 版权声明: 1、通讯模块代码版权归作者所有; 2、未经许可不得全部或部分用于任何项目开发; 3、未经许可不得部分修改后再利用源码。 免责声明: 1、 由于设计缺陷或其它Bug造成的后果,作者不承担责任; 2、未经许可的使用作者不提供任何技术支持服务。 权利和义务: 1、任何获得源码并发现Bug的个人或单位均有义务向作者反映; 2、作者保留追究侵权者法律责任的权利。 二、开发背景 部分代码由前项目分离而来,尚未有应用考验,但对于初学者学习和进阶有很大帮助。性能上尚未有定论,但应该不会令你失望。 三、功能说明 1、可以关闭Socket的Buffer; 2、可以关闭MTU(不等待MTU满才发送); 3、可以多IP或多端口监听; 4、可以重用socket(主动关闭除外); 5、可以0缓冲
接收
(Socket的Buffe = 0时,避免过多的锁定内存页); 6、可以0缓冲连接(客户端仅连接,不一定立即发数据); 7、可以条件编译: a、是否使用内核Singly-linked lists; b、是否使用处理线程(工作线程和处理线程分开); c、是否使用内核锁来同步链表。 8、可以实现集群服务器模式的通讯(有客户端socket); 9、可以单独设置每个连接的Data项来实现连接和Usernfo的关联; 10、每个线程有OnBegin和OnEnd,用于设置线程独立的对象(数据库会话对象); 11、可以提供详细的运行情况,便于了解
IOC
P下的机制,以及进行调试分析; 12、可以发起巨量连接和数据(需要硬件配置来支持)。
ioc
p服务器客户端混合框架
//一个简单的使用例子 //连接远程服务器成功 或
接收
到一个远程连接时,本函数将会被
ioc
.dll回调.在本函数中,应该向客户端列表中添加节点,记得加锁 // //2.s :套接字句柄,标志着一个新的连接 //3.u_addr:对端的IP地址,网络字节序 //4.u_port:对端的端口号,网络字节序 //5.flag :如果是本地连接上了一个远程服务器,flag值为0,或者,是
接收
到一个远程客户端的连接,这时,flag值为1 //6.返回值:返回一个自定义的值,这个值将在其他回调函数中作为参数传递(注意:就如套接字句柄一样,这个值也最 //好能标志一个连接,比如,客户端列表的某个节点的指针,假设用STL中的MAP来维护客户端列表,那么用KEY作为返回值也不错。) long _stdcall
ioc
_call_connect(H
IOC
h
Ioc
,HINT s,long u_addr,long u_port,long flag) { long res=0; printf("socket(%d) connected\n",s); return res; } //断开与远程服务器的连接 或 远程客户端断开,本函数将会被
ioc
.dll回调.在本函数中,你可以删除客户节点,记得加锁 //s :套接字句柄,标志着哪个连接断开了(在本回调函数返回之前,套接字句柄s不可能被重新利用,所以,用s作为关键字构建客户端列表也是没有
问题
的) //res:
ioc
_call_connect回调函数返回的那个值,如果它是客户端列表的某个节点的话,那么可以删除了。 void _stdcall
ioc
_call_disconnect(H
IOC
h
Ioc
,HINT s,long res,long flag) { printf("socket(%d) disconnected\n",s); } //当
ioc
内部一收到数据就会回调本函数,所谓数据有可能是多个数据包,也有可能是一个不完整的数据包 //h
Ioc
,s,flag都不再多做解释 //res :
ioc
_call_oprate_dat和
ioc
_call_disconnect一定是被线性回调的,不可能存在同时执行的情况,所以,res如果指向某个节点的话,在本函数中可以不加锁地尽情访问,在本函数返回之前,res不会被释放掉 //hArg:数据调度句柄 //data:数据 //len :数据大小 //返回值:返回剩余未处理完的字节数 long _stdcall
ioc
_call_oprate_dat(H
IOC
h
Ioc
,HARG hArg,HINT s,long res,long flag,char *data,long len) { //假如数据包格式是这样: //struct DATAPACK //{ // long size; long cmd; ...... //}; //如果是这样的话,那么典型的处理方法如下: char *p=data; long size_res=len;//收到数据的总字节数 long size_per;//其中某一个数据包的字节数 while(1) { if(size_res<4) return size_res;// size_per=*(long*)(p+0x00);//取数据包的实际长度 if(size_per<0 || size_per>某个最大值) { ::
ioc
Common_CloseSocket(h
Ioc
,s); return 0; } if(size_res
iocCommon_DispatchMessage(h
Ioc
,hArg,msg);//hArg就只有这么一个作用 } p+=size_per; size_res-=size_per; } } //阻塞数据处理线程回调函数 void _stdcall
ioc
_call_oprate_msg(H
IOC
h
Ioc
,void *msg) { //处理数据包 ::free(msg);//根据谁分配谁释放的原则,释放msg } int main() { ::
ioc
Common_Startup(); long addr_con=(long)
ioc
_call_connect; long addr_dis=(long)
ioc
_call_disconnect; long addr_dat=(long)
ioc
_call_oprate_dat; long addr_msg=(long)
ioc
_call_oprate_msg;//这个参数是可选的,可以不要专门的阻塞数据处理线程 H
IOC
h
Ioc
=::
ioc
Common_Create(3072,128,addr_con,0,addr_dis,0,addr_dat,0,addr_msg,0);//创建
IOC
::
ioc
Common_SetOprateThread(h
Ioc
);//增加一个工作线程 ::
ioc
Common_SetOprateThread(h
Ioc
);//增加一个工作线程 //启动服务器,内部循环调用阻塞的accept函数,
ioc
不考虑客户端连接服务器有多困难,而只考虑如何高效地进行数据传输 //可以再创建几个线程,多调用几个
ioc
Server_Start,各个
ioc
Server_Start绑定不同端口也可以 ::
ioc
Server_Start(h
Ioc
,NULL,6800); ::
ioc
Common_Cleanup(); return 0; }
网络编程
18,356
社区成员
64,214
社区内容
发帖
与我相关
我的任务
网络编程
VC/MFC 网络编程
复制链接
扫一扫
分享
社区描述
VC/MFC 网络编程
c++
c语言
开发语言
技术论坛(原bbs)
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章