IOCP断开socket的同步问题

skyair624 2009-07-29 12:00:34
WSASend的操作为:把指定的(WSABUF)缓冲区数据复制到IOCP内部的传输控制缓冲区
WSARecv的操作为:把指定的(WSABUF)缓冲区数据复制出IOCP内部的缓冲区
!!!如果上面有错误请指点,谢谢


上面的结论引出的问题是:如果当一个worker线程调用closesocket强制关闭一个连接良好的socket时,IOCP内部正好用这个socket发送或是接收数据(正在进行),那么会出现什么情况?
...全文
210 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
skyair624 2009-07-31
  • 打赏
  • 举报
回复
看来主要是API不熟悉
skyair624 2009-07-31
  • 打赏
  • 举报
回复
哎,就是等楼上的解释,给分给分了!
gotooker 2009-07-31
  • 打赏
  • 举报
回复
应该是和SO_LINGER的设置有关吧。设置0立刻关闭。清除资源。在设定时间内等待接受或发送,然后关闭清除资源
skyair624 2009-07-31
  • 打赏
  • 举报
回复
不知道什么时候能碰上怎么做实验呢?
worker线程谁知道什么时候会跟IOCP内部的服务线程碰上呢,很小的概率。
不知道把传输的数据弄得特别大会不会有那种情况?
vagrantisme 2009-07-31
  • 打赏
  • 举报
回复
一般是先调用CancelIo 再调用CloseSocket。
直接closesocket,先前投递过的IO会被取消,直接进入完成队列,且传输字节=0。


自己做个试验就可以得出结论的。
skyair624 2009-07-31
  • 打赏
  • 举报
回复
明白楼上的意思,但是我的意思是要在server端实现socket的管理功能,也就是说server可以主动关闭某个指定socket,而我在server主动关闭socket的方法就是用PostQueuedCompletionStatus发送一个0的包给IOCP来实现关闭的,但我担心的是在我的worker线程closesocket的时候IOCP内部的线程如果“正在”(不是“阻塞等待或检测”)SEND或RECV数据会出现什么情况?
fangle6688 2009-07-31
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 skyair624 的回复:]
恩,谢楼上二位,不过,如果是有那种情况,会是什么样子?
是内部有同步还是出现内存违规?

不过我感觉内部应该做了同步,但是不能确定,所以如果没有把握不敢保证代码的稳定。

还有个就是如果shutdown了那些操作,会不会有完成消息?
[/Quote]


如果你打算在shutdown之后马上closesocket,其实你根本没必要shutdown
合理的“优雅关闭”是先shutdown,让对方先收到FD_CLOSE事件
然后投递一个WSARecv
等某个WSARecv完成并且接收字节=0时,说明对方已closesocket
这时候你closesocket才算是“优雅的”

不管你是shutdown+closesocket还是直接closesocket
你先前投递过的IO操作都会进入完成队列

直接closesocket,先前投递过的IO会被取消,直接进入完成队列,且传输字节=0
skyair624 2009-07-30
  • 打赏
  • 举报
回复
恩,谢楼上二位,不过,如果是有那种情况,会是什么样子?
是内部有同步还是出现内存违规?

不过我感觉内部应该做了同步,但是不能确定,所以如果没有把握不敢保证代码的稳定。

还有个就是如果shutdown了那些操作,会不会有完成消息?
雪影 2009-07-29
  • 打赏
  • 举报
回复
没有研究过,
关注,学习。
sun007700 2009-07-29
  • 打赏
  • 举报
回复
shutdown,写错
sun007700 2009-07-29
  • 打赏
  • 举报
回复
"如果当一个worker线程调用closesocket强制关闭一个连接良好的socket时,IOCP内部正好用这个socket发送或是接收数据(正在进行),那么会出现什么情况? "
当然是不能再接收和发送了啊,socket都关闭了。一般关闭socket时,先shutdows(socket,2),然后再closesocket,这样可以让send和recv操作完成以后再关闭socket,称为优雅关闭。
百事烟 2009-07-29
  • 打赏
  • 举报
回复
都没有copy过程的,是重叠IO过程
WSASend 把指定的BUF重叠到要发送的端口,准备发送
WSARecv 把指定的BUF重叠到要接收的端口,准备接收

如果当一个worker线程调用closesocket强制关闭一个连接良好的socket时,相应函数直接返回错误代码
Leo_red 2009-07-29
  • 打赏
  • 举报
回复
同意2楼
songtao_01 2009-07-29
  • 打赏
  • 举报
回复
强制关闭,返回错误,系统清理相应socket的缓冲区。

WSASend的操作为:把指定的(WSABUF)缓冲区数据复制到socket内部的传输控制缓冲区
WSARecv的操作为:把socket内部的缓冲区复制到指定的(WSABUF)缓冲区数据
udknight 2009-07-29
  • 打赏
  • 举报
回复
先调用shutdown
结构层次及相互联系 (1)、工作线程:响应连接的IO投递返回并负责投递读请求,并将IO返回结果投递给处理线程,可设定参数决定工作线程数量; (2)、处理线程:处理线程调用回调函数将信息传递给应用层或协议栈,可设定参数决定工作处理数量; (3)、看守线程:响应Accept事件调用AcceptEx,检测连接和心跳超时 ,将信息投递给工作线程,模块仅有一个看守线程。 1. 技术要求 (1)、线程同步:Lock指令、临界段; (2)、主要Socket API:WSASend、WSARecv、AcceptEx、DisconnectEx; (3)、内存管理:连接池(句柄重用)、内存池; (4)、数据0拷贝:通过内置处理线程,上层应用可以避免自建线程池及复制数据的过程。同时提供GBuf内存分配功能,应用层获得分配地址及填充数据之后亦可直接投递给内核/驱动层; (5)、数据顺序同步:同一个连接同时只有一个处理线程响应其IO事件; (6)、IO请求投递:单投递读、多投递写; (7)、0缓冲读投递:可条件编译实现,以适用大规模连接要求。 (8)、超时机制:可设置空连接(连接不发送数据)超时时间以防止DOS攻击,也可设置心跳超时时间防止网络故障导致的现有连接成为虚连接避免耗尽系统资源。 (9)、接口技术:API、回调函数、客户句柄(客户连接句柄)。 (10)、主、被动发送:不使用HASH、MAP及LIST技术,即可提供安全可靠高效的客户连接句柄,以实现服务器端主被动发送数据功能; (11)、PerHandleData的回收不以IO投递的计数器或链表来做依据但仍能安全回收,同时尽量避免在高频的读写操作时做其他无关的操作以提高读写效率。 (12)、处理线程和工作线程有着良好分工界限,繁重的工作交给处理线程完成,工作线程工作量最大限度的减少,仅响应投递返回及读投递的操作; (13)、支持AWE,模块自动识别AWE是否开启(需手动开启),“否”则使用虚拟内存机制。 2. 功能要求 (1)、多IP多端口监听,每个监听可设置不同的回调函数,以高效的区别处理数据 (2)、可设置每秒最大的连接并发量和空连接(连接不发数据)超时时间以防止DOS攻击造成的服务瘫痪、具有心跳处理(防网络异常造成的虚连接)功能 (3)、不加协议的透明传输,可适用广泛的网络通讯环境 (4)、可现实主、被动发送数据,但不会因兼顾主动发送而额外增加降低效率的工作 (5)、内置处理线程,上层应用可不必自建线程池处理数据,所有IO事件按顺序调用回调函数并可以在回调函数内直接处理数据,不必担心多线程造成的接收数据乱序的问题。 (6)、高效率的数据对应关联机制,在初次连接并根据登录数据设置每个连接对应的宿主(Owner)之后,再接收的数据即可立即获得该连接对应的宿主,而不必再做额外的查询工作,并且模块内部采用的是指针关联方式,对于长连接、主动发送的服务器系统而言是高效率的。 (7)、可兼容IPv6 3. 注意事项 因硬件环境和应用环境不同,不合理的配置会出现效率及性能上的问题,因此以下情况出现时,请务必与作者联系以确保获得更好的参数配置: (1)、连接量超过1000个的。超过的应结合具体硬件配置和网络带宽等因素综合设定运行参数。 (2)、带宽使用率超过20%的。工作线程和处理线程数量的设置也是综合考虑数据吞吐量和数据处理负载的因素来设置的,过多的线程会在调度上浪费时间,同时也应该综合考虑线程优先级别来设置工作线程和处理线程数量,两者的设置也不一定能相等。 (3)、服务器端有主动发送需求的、短连接(含网络故障造成的连接断开)出现频率高的。 压力测试工具介绍: 一、 使用G-TcpClient模块 二、 可以设定间隔时间发起大规模长、短连接 三、 可以发起密集数据包,包括即时和定时发送,1M的光纤带宽最大可以达到100K/S(单向)以上,100M本地网最大可以达到10M/S(单向)以上 四、 数据发送仅由一个独立线程但当,每点击一次Connect就创建一个线程根据当前参数发起连接。 五、 测试前提:服务器接收客户端数据后立即原样返回给客户端
说明 一、受限制库Dll和lib说明: 库文件G-TcpServer.lib、G-TcpServer.Dll是受限制的试用版本和Demo配套。 1、最大连接不能超过50 2、发送字节数不能超过50 3、不能设置0读投递、无超时机制 4、其他功能限制 二、版本解读说明 1、版本名带T的表示是受限制的试用版 2、版本名带bata表示非正式版 3、版本名带WChar表示支持WideChar 4、版本号以时间格式累加计数(60进1)和显示 三、文件“G-TcpServer无限制体验版.exe”是无限制的体验版。 四、文件夹 1、Demos文件夹是VC Lib、Dll库及Delphi2010的例程源码,供开发学习 2、G-Sockets文件夹是Lib和Dll库的Delphi和VC的头文件 3、Release\G-Sockets\Dll文件夹是动态库的输出文件夹 4、Release\G-Sockets\Lib文件夹是静态库的输出文件夹 1、模块包含处理线程、工作线程和看守线程。 工作线程负责IO投递工作,并响应投递返回,再把接收的数据投递给处理线程,处理线程调用回调函数给应用层,以此可以在通讯层和应用层之间现实0拷贝数据的功能。模块只有一个看守线程,负责:a、响应Accept事件并投递接受队列;b、效验接受超时(即只连接不发数据)断开连接,防止空连接;c、效验空闲超时(即心跳超时)断开连接。 按工作量来分,最繁重的是处理线程,其次是工作线程,最闲的是看守线程。可通过OnThread事件回调函数设置线程权限。在此线程模式下,应用层可以在回调函数里处理数据而不必再建立另外的数据处理线程池。 2、线程平衡 为使连接能平衡使用处理线程,每个连接同时只有一个处理线程处理工作线程投递过来的IO返回事件并调用回调函数通知应用层。 3、收发平衡 为使连接能平衡使用IO设备,每个连接同时只能投递一个读请求,并通过线程平衡机制保证接收的数据是按顺序的被处理线程处理及通过回调函数传递给应用层;同时也只能投递一个写请求,其余写请求都按顺序放在写队列里面。读写同步都使用临界段。 4、0拷贝技术 接收数据0拷贝看1项;提供GTcpSvr_AllocGBuf()、GTcpSvr_FreeGBuf()和GTcpSvr_PostSendGBuf()三个函数实现发送数据的0拷贝。 5、0读投递 为避免内核锁定分页内存过多,可通过设置来采用0读投递来降低吞吐性能从而实现大连接量。 6、HndData回收 HndData回收有多种方法,但额外会在收发数据这两个频率操作上增加工作量,因此尽量避免在这两个操作时做太多的工作是有必要的。模块均不采用“投递计数”或“投递链表”的方式来判断回收HndData的时机,而是一旦断线立即回收,其他未决投递继续返回时只处理IoData,不对HndData做任何写操作。同时为避免HndData刚收回来但其未决投递还没有完全返回之前就立即被利用的可能性,HndData池采用了FIFO双锁并发链表,该链表通过ExNumber值来实现在最大连接情况下HndData池还有ExNumber个数量使链表不为NULL,通过设置ExNumber数量可实现控制链表末端的HndData出列时间,在这个时间内可以保证断开刚回收的HndData的未决投递能够完全返回。 HndData池,初始时如下: HD1 + HD2 + HD... + HDMaxConnection + HDEx1 + HDEx2 + HDEx... + HDExNumber | | Head------------------------------------------------------------------Tail 达到最大连接时如下: HDEx1 + HDEx2 + HDEx... + HDExNumber | | Head---------------------------Tail 断开回收一个HndData(HD)后如下: HDEx1 + HDEx2 + HDEx... + HDExNumber + HD | | Head-------(需要T时间HD才能出列)------Tail 注:T可以通过控制ExNumber值来实现,假定每秒最大可以处理C个连接和断开,需要延时T秒所有未决投递才会完全回收,那么:ExNumber = T * (MaxConnection / C)。实际上每个连接未决投递非常少(因为读写是单投递的),并且工作线程并不处理数据工作量不大,因此T很短,模块默认是3秒。对于服务器而已,一秒能接受的连接量是可知预计的,模块默认是1万,假定MaxConnection=C所以ExNumber是3万。但实际应用中,正常情况下连接率远少于1万/S,尤其是长连接的服务器,即使是短连接的服务器也不会发生这样的连接率。可能的情况是DOS,如果是影响也不大,因为还有MaxConnection控制,超过这个数的连接就立即被CloseSocket了。和频率高的数据收发相比,断线、连接的频率远少于它,在频率低的地方上多做多点工作总比在频率高的地方多做一点工作的好。 7、可伸缩性 IoData数量可根据初始需要设置,资源不足时模块自动向系统申请内存。为保证HndData的安全性,HndData池还设置了延时出列,刚回收的HndData入列时间必须超过3(或更长)秒钟,如果未达到3秒的,模块自动向系统申请内存。 8、内存管理 IoData和HndData均采用VirtualAlloc和VirtualFree来向系统操作内存。IoData池采用原子函数InterlockedCompareExchange来操作进出栈。HndData采用单向FIFO双锁并发链表来管理出入列操作。其他小内存需求的均采用静态数组或new操作。 五、内存需求 每个IoData等于一个分页内存大小,信息头大小为36Byte,有效使用内存是4060Byte,因此对GTcpSvr_AllocGBuf获得的内存写入时不应该超过4060(调用GTcpSvr_GetGbufSize获得),所有IoData占用系统内存是:IoDataCount * PageSize(4096)。每个HndData大小是128Byte,加上每个Socket分配时耗内存约是:540Bytes(此为估计值,应以MS技术文档为准),所有HndData耗系统内存是:HndDataCount * MAX_HNDDATA_AND_SOCKET_SIZE(128 + 540)。其他变量和数组可能耗得内存在10M之下。 综上,整个模块需求内存量是:UseMemSize = IoDataCount * PageSize + HndDataCount * MAX_HNDDATA_AND_SOCKET_SIZE + 10M。
说明 一、本压缩包含: 1、Demo源码,位于:\Demos\G-TcpServerLibDemo\G-TcpServerLibDemo.vcproj 2、G-TcpServer模块头文件文件,位于:\G-Sockets\G-TcpServer.h(模块核心文件) 3、G-TcpServer模块Lib文件,位于:\G-Sockets\G-TcpServer.lib(模块核心文件) 4、无限制Demo exe文件:G-TcpServerLibDemo1.0.exe 二、受限制库G-TcpServer.lib说明: 库文件G-TcpServer.lib是受限制的试用版本和Demo配套。 1、最大连接不能超过100 2、发送字节数不能超过128 3、不能设置0读投递 4、其他功能限制 三、版本解读说明 1、版本名带T的表示是受限制的试用版,参阅二 2、版本名带bata表示非正式版 3、版本名带WChar表示支持WideChar 4、版本号以时间格式累加计数(60进1)和显示 四、技术说明 1、模块包含处理线程、工作线程和看守线程。 工作线程负责IO投递工作,并响应投递返回,再把接收的数据投递给处理线程,处理线程调用回调函数给应用层,以此可以在通讯层和应用层之间现实0拷贝数据的功能。模块只有一个看守线程,负责:a、响应Accept事件并投递接受队列;b、效验接受超时(即只连接不发数据)断开连接,防止空连接;c、效验空闲超时(即心跳超时)断开连接。 按工作量来分,最繁重的是处理线程,其次是工作线程,最闲的是看守线程。可通过OnThread事件回调函数设置线程权限。在此线程模式下,应用层可以在回调函数里处理数据而不必再建立另外的数据处理线程池。 2、线程平衡 为使连接能平衡使用处理线程,每个连接同时只有一个处理线程处理工作线程投递过来的IO返回事件并调用回调函数通知应用层。 3、收发平衡 为使连接能平衡使用IO设备,每个连接同时只能投递一个读请求,并通过线程平衡机制保证接收的数据是按顺序的被处理线程处理及通过回调函数传递给应用层;同时也只能投递一个写请求,其余写请求都按顺序放在写队列里面。读写同步都使用临界段。 4、0拷贝技术 接收数据0拷贝看1项;提供GTcpSvr_AllocGBuf()、GTcpSvr_FreeGBuf()和GTcpSvr_PostSendGBuf()三个函数实现发送数据的0拷贝。 5、0读投递 为避免内核锁定分页内存过多,可通过设置来采用0读投递来降低吞吐性能从而实现大连接量。 6、HndData回收 HndData回收有多种方法,但额外会在收发数据这两个频率操作上增加工作量,因此尽量避免在这两个操作时做太多的工作是有必要的。模块均不采用“投递计数”或“投递链表”的方式来判断回收HndData的时机,而是一旦断线立即回收,其他未决投递继续返回时只处理IoData,不对HndData做任何写操作。同时为避免HndData刚收回来但其未决投递还没有完全返回之前就立即被利用的可能性,HndData池采用了FIFO双锁并发链表,该链表通过ExNumber值来实现在最大连接情况下HndData池还有ExNumber个数量使链表不为NULL,通过设置ExNumber数量可实现控制链表末端的HndData出列时间,在这个时间内可以保证断开刚回收的HndData的未决投递能够完全返回。 HndData池,初始时如下: HD1 + HD2 + HD... + HDMaxConnection + HDEx1 + HDEx2 + HDEx... + HDExNumber | | Head------------------------------------------------------------------Tail 达到最大连接时如下: HDEx1 + HDEx2 + HDEx... + HDExNumber | | Head---------------------------Tail 断开回收一个HndData(HD)后如下: HDEx1 + HDEx2 + HDEx... + HDExNumber + HD | | Head-------(需要T时间HD才能出列)------Tail

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧