IOCP之超时连接关闭Socket

hnu_0720 2015-07-11 09:23:58
最近在学习IOCP完成端口,现在遇到一个问题想请教一下大家.
我准备定时检查所有Socket的连接,如果发现有过长时间没有交互数据,就关闭这个连接.
现在问题来了:怎么关闭呢?
我的打算是用PostQueuedCompletionStatus 这个API,然后在线程里面 GetQueuedCompletionStatus 的时候 关闭这个连接
我现在担心的是,由于是多线程的,如果在我关闭的时候,这个Socket又开始交互数据了?
大家又什么好的做法了,请指导一下.谢谢了
...全文
282 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
hnu_0720 2015-07-13
  • 打赏
  • 举报
回复
引用 5 楼 xian_wwq 的回复:
[quote=引用 2 楼 hnu_0720 的回复:] [quote=引用 1 楼 xian_wwq 的回复:] 通过PostQueuedCompletionStatus 处理是正确的 在工作线程中把closesocket的操作收拢到一处 就没有问题了
刚学习,不清楚完成端口的内部操作,能说详细一点吗? 我的业务流程是这样的.最开始的时候我接收到了客户端的连接,然后投递了WSARecv用来接收客户端发送的数据, 但是客户端很久也没有发送数据,我就判定这个连接是一个恶意连接或者是已经断开的连接, 通过PostQueuedCompletionStatus 给完成端口发送一个完成信息,然后在工作线程里面处理这个完成信息的时候closesocket. 我现在的疑问是: 1) 在我PostQueuedCompletionStatus的时候,完成端口队列已经有一个WSARecv的完成信息了 2) 在我PostQueuedCompletionStatus的之后,完成端口队列接收到了一个WSARecv的完成信息. 这个时候我在一个线程里面closesocket,而另外的一个线程又在做业务.怎么办呢?[/quote] 从业务流程来说,都是一问一答,所以不会出现多个线程同时处理一个socket; 单个socket,如果close掉,这个socket上所有的未完成的投递就会返回。 在Server侧肯定有个客户端socket的容器,如果返回投递的socket在容器中已经找不到, 说明已经被关闭了,直接释放资源就可以 [/quote] 业务上的确是你说的这样,不过我现在是在一个单独的线程轮询所有的SOCKET,判断SOCKET是否超时,如果超时就关闭连接,我就是怕我关闭连接的时候,其他线程还在使用这个SOCKET
xian_wwq 2015-07-13
  • 打赏
  • 举报
回复
引用 2 楼 hnu_0720 的回复:
[quote=引用 1 楼 xian_wwq 的回复:] 通过PostQueuedCompletionStatus 处理是正确的 在工作线程中把closesocket的操作收拢到一处 就没有问题了
刚学习,不清楚完成端口的内部操作,能说详细一点吗? 我的业务流程是这样的.最开始的时候我接收到了客户端的连接,然后投递了WSARecv用来接收客户端发送的数据, 但是客户端很久也没有发送数据,我就判定这个连接是一个恶意连接或者是已经断开的连接, 通过PostQueuedCompletionStatus 给完成端口发送一个完成信息,然后在工作线程里面处理这个完成信息的时候closesocket. 我现在的疑问是: 1) 在我PostQueuedCompletionStatus的时候,完成端口队列已经有一个WSARecv的完成信息了 2) 在我PostQueuedCompletionStatus的之后,完成端口队列接收到了一个WSARecv的完成信息. 这个时候我在一个线程里面closesocket,而另外的一个线程又在做业务.怎么办呢?[/quote] 从业务流程来说,都是一问一答,所以不会出现多个线程同时处理一个socket; 单个socket,如果close掉,这个socket上所有的未完成的投递就会返回。 在Server侧肯定有个客户端socket的容器,如果返回投递的socket在容器中已经找不到, 说明已经被关闭了,直接释放资源就可以
hnu_0720 2015-07-12
  • 打赏
  • 举报
回复
引用 1 楼 xian_wwq 的回复:
通过PostQueuedCompletionStatus 处理是正确的 在工作线程中把closesocket的操作收拢到一处 就没有问题了
刚学习,不清楚完成端口的内部操作,能说详细一点吗? 我的业务流程是这样的.最开始的时候我接收到了客户端的连接,然后投递了WSARecv用来接收客户端发送的数据, 但是客户端很久也没有发送数据,我就判定这个连接是一个恶意连接或者是已经断开的连接, 通过PostQueuedCompletionStatus 给完成端口发送一个完成信息,然后在工作线程里面处理这个完成信息的时候closesocket. 我现在的疑问是: 1) 在我PostQueuedCompletionStatus的时候,完成端口队列已经有一个WSARecv的完成信息了 2) 在我PostQueuedCompletionStatus的之后,完成端口队列接收到了一个WSARecv的完成信息. 这个时候我在一个线程里面closesocket,而另外的一个线程又在做业务.怎么办呢?
hnu_0720 2015-07-12
  • 打赏
  • 举报
回复
引用 3 楼 mengfeihong 的回复:
"标准"的,符合微软范例的iocp用法,对同一socket的线程调用是串行的,也就是对同一个socket,不会有并发的线程,这是我之前的研究结果。
好的,谢谢你.
蒙飞鸿 2015-07-12
  • 打赏
  • 举报
回复
"标准"的,符合微软范例的iocp用法,对同一socket的线程调用是串行的,也就是对同一个socket,不会有并发的线程,这是我之前的研究结果。
xian_wwq 2015-07-11
  • 打赏
  • 举报
回复
通过PostQueuedCompletionStatus 处理是正确的 在工作线程中把closesocket的操作收拢到一处 就没有问题了
结构层次及相互联系 (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
第1 章 NetBIOS 1 1.1 Microsoft NetBIOS 2 1.1.1 LANA 编号 2 1.1.2 NetBIOS 名字 4 1.1.3 NetBIOS 特性 6 1.2 NetBIOS 编程基础 7 1.3 常规NetBIOS 例程 8 1.3.1 会话服务器:异步回调模型 15 1.3.2 会话服务器:异步事件模型 20 1.3.3 NetBIOS 会话客户机 24 1.4 数据报的工作原理 28 1.5 其他NetBIOS 命令 40 1.5.1 适配器状态 40 1.5.2 查找名字 42 1.5.3 将传送协议同LANA 编号对应起来 43 1.6 平台问题 43 1.6.1 Windows CE 44 1.6.2 Windows 9x 44 1.6.3 常规问题 44 1.7 小结 44 第2 章 重定向器 45 2.1 通用命名规范 45 2.2 多UNC 提供者 47 2.3 网络提供者 47 2.4 重定向器简介 48 2.5 服务器消息块 48 2.6 安全问题 49 2.6.1 安全描述符 49 2.6.2 访问令牌 51 2.7 网络安全 51 2.8 一个实例 52 2.9 小结 53 第3 章 邮槽 54 3.1 邮槽实施细节 54 3.1.1 邮槽的名字 54 3.1.2 消息的长度 55 3.1.3 应用程序的编译 56 3.1.4 错误代码 57 3.2 基本客户机/服务器 57 3.2.1 邮槽服务器的详情 57 3.2.2 邮槽客户机的详情 59 3.3 其他邮槽API 61 3.4 平台和性能问题 62 3.4.1 8.3 字符名字限制 62 3.4.2 不能取消“凝结”的I/O 请求 62 3.4.3 超时引起的内存废弃 64 3.5 小结 65 第4 章 命名管道 66 4.1 命名管道的实施细节 66 4.1.1 命名管道命名规范 67 4.1.2 字节模式及消息模式 67 4.1.3 应用程序的编译 67 4.1.4 错误代码 68 4.2 客户机与服务器的基础 68 4.2.1 服务器的细节 68 4.2.2 高级服务器的细节 74 4.2.3 客户机的细节 81 4.3 其他API 调用 83 4.4 平台和性能问题 86 4.5 小结 87 第二部分 Winsock API 第5 章 网络原理和协议 89 5.1 协议的特征 89 5.1.1 面向消息 89 5.1.2 面向连接和无连接 91 5.1.3 可靠性和次序性 91 5.1.4 从容关闭 92 5.1.5 广播数据 92 5.1.6 多播数据 92 5.1.7 服务质量 92 5.1.8 部分消息 93 5.1.9 路由选择的考虑 93 5.1.10 其他特征 93 5.2 支持的协议 93 5.2.1 支持的Win32 网络协议 93 5.2.2 Windows CE 网络协议 94 5.3 Winsock 2 协议信息 94 5.4 Windows 套接字 97 5.5 具体平台的问题 99 5.6 选择适当的协议 100 5.7 小结 100 第6 章 地址家族和名字解析 102 6.1 IP 102 6.1.1 TCP 102 6.1.2 UDP 102 6.1.3 定址 102 6.1.4 创建套接字 105 6.1.5 名字解析 105 6.2 红外线套接字 107 6.2.1 定址 107 6.2.2 名字解析 108 6.2.3 红外线设备列举 108 6.2.4 查询IAS 110 6.2.5 创建套接字 111 6.2.6 套接字选项 112 6.3 IPX/SPX 112 6.3.1 编址 112 6.3.2 创建套接字 112 6.4 NetBIOS 115 6.4.1 定址 115 6.4.2 创建套接字 116 6.5 AppleTalk 117 6.5.1 定址 117 6.5.2 AppleTalk 名的注册 118 6.5.3 AppleTalk 名的解析 119 6.5.4 创建套接字 124 6.6 ATM 124 6.6.1 定址 125 6.6.2 创建套接字 128 6.6.3 把套接字和SAP 绑定在一起 129 6.6.4 名字解析 130 6.7 Winsock 2 支持的其他函数 130 6.8 小结 131 ......

18,356

社区成员

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

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