为了在IOCP中使SOCKET句柄复用,我使用了DisconnectExt函数,一般情况下客户端与服务端建立连接后,服务端会投递一个WSARecv例程给IOCP以接收来自客户端的数据,而服务端主动断开连接时会投DisconnectEx例程。问题描述:
当服务端主动提交DisconnectEx例程后正常情况是先收到WSARecv完成事件 然后收到DisconnectEx完成事件并且在DisconnectEx事件中做一些资源清理工作然后把此句柄提交给AcceptEx队列中。但问题是有时候先接收到的是DisconnectEx完成事件然后再接收到是WSARecv完成事件,这种情况造成一些问题比如当清理工作完成后IOCP会把这个SOCKET分配给一个新的连接,这个时候可能收到的WSARecv完成事件是原来旧的连接上的。我在DisconnectEx之前也用过了CancelEx来取消IO但无济于世,问教大家有什么办法能在接收到断开事件前让WSARecv完成事件先达到,这样才能顺序条理的释放句柄上的资源。
当服务端主动提交DisconnectEx例程后正常情况是先收到WSARecv完成事件 然后收到DisconnectEx完成事件并且在DisconnectEx事件中做一些资源清理工作然后把此句柄提交给AcceptEx队列中。但问题是有时候先接收到的是DisconnectEx完成事件然后再接收到是WSARecv完成事件,这种情况造成一些问题比如当清理工作完成后IOCP会把这个SOCKET分配给一个新的连接,这个时候可能收到的WSARecv完成事件是原来旧的连接上的。我在DisconnectEx之前也用过了CancelEx来取消IO但无济于世,问教大家有什么办法能在接收到断开事件前让WSARecv完成事件先达到,这样才能顺序条理的释放句柄上的资源。
解决方案 »
- VC写的串口编程为什么不能显示中文。
- dbf类访问2Gb以上的dbf文件实例
- 如何用isapi的dll能获取到可户的ip地址?
- CComObject 能否象智能指针一样绑定接口?
- 请教高手或理论功底学的扎实的人:在VC++里,有了内存地址,怎样把该地址对应的一段数据“翻译”成字符?
- 寻求“冲击波”的中文补丁链接。
- 请问大家,在Opengl中,怎样用photoshop生成的texture图片啊
- 请问如何在程序里调用其他软件编的应用程序(EXE文件)?????
- 为什么我的VC6.0编译不管有多少错误都只提示一个错误
- 背单词程序计划
- 向别的进程窗口发鼠标消息没用,要发mouse_event才行?为什么?怎么解决?
- ffmpeg解压h.264数据的时候总是延迟一帧
我目前确实是这样做的,我的想法就是有没有其它更好的方法来解决这个问题!希望大家畅所欲言!
在处理完一个IO请求后,使用InterlockedDecrement计数
当要断开连接时,标记一个状态Disconnecting=True,投递一个IO通知断开连接(PostDisconnectEx),同时计数+1
收到DisconnectEx的IO时,触发OnDisconnect后,计数-1所有可能触发断线的地方,判断Disconnecting是否=True,若Disconnecting=True时,判断计数是否=0
计数=0时,在一个统一的接口(ReleaseClient)回收相关资源有过程触发ReleaseClient时,表示所有IO返回完成,可以安全回收上下文资源
一个AcceptEx和WSArecv,
一个DisconnectEX,
一个WSASend.结构大致如下:
struct OVERLAPPEDEX{
OVERLAPPED ol;
ioctl *ctl;
char *buf;
unsigned long len;
int opt;//表示用来IO操作的模式:
//FD_READ=WSARecv事件
//FD_WRITE=WSASend事件
//FD_ACCEPT=AcceptEx事件
//FD_CLOSE=DisconnectEx事件
};同时在class ioctl中,有一个int opts; 它可以是 FD_READ, FD_WRITE, FD_ACCEPT, FD_CLOSE的任意组合。
在投递操作之前,OVERLAPPEDEX.opt=具体操作;时,ioctl.opts |= 具体操作;
在事件完成时,ioctl.opts ^= OVERLAPPEDEX.opt;
读写都加锁。这样子处理之后,那么服务端只要满足以下几个条件,就可以正确的处理这种并发问题:
1、投递AcceptEx时,必须保证ioctl.opts为0,也就是所有事件都已经返回。
2、FD_ACCEPT是一个独立的值,绝对不会包含其他操作共存,当ioctl.opts==FD_ACCEPT时,拒绝之后的所有操作。
3、FD_CLOSE可以与FD_READ,FD_WRITE共存,但是一个套接字在其有效期内,只允许投递一次FD_CLOSE。
4、一个投递过FD_CLOSE的套接字,拒绝之后的FD_READ与FD_WRITE操作。accept:192,168,2,11:65405
2019/09/21 06:40:50 ioctl::read ok!
2019/09/21 06:40:50 IO完成:1, bytes:7
接收完毕!
收到客户端数据:啦啦啦
2019/09/21 06:40:50 ioctl::_write ok!
2019/09/21 06:40:50 IO完成:2, bytes:13
发送完毕!
2019/09/21 06:40:50 ioctl::read ok!
2019/09/21 06:40:50 ioctl::disconnect ok!
2019/09/21 06:40:50 IO完成:1, bytes:0
2019/09/21 06:40:50 IO完成:32, bytes:0
2019/09/21 06:40:50 ioctl::accept ok!看日志可以知道,ioctl::read与ioctl::disconnect在一起调用了,之后也是并发完成,到最后一个事件完成时,才去把套接字acceptex回去。
题外话1:异步网络IO会带来发送数据积压的问题,这个问题没有什么好办法来解决,只能限制最大积压数,超过这个数量,要么断开连接,要么就把数据抛弃掉。题外话2:异步网络IO模型并不适合IOCP来处理,应该考虑去linux使用epoll,因为异步网络IO追求的不是并发量。题外话3:C1M以上的并发量时,IOCP将全面超越epoll,因为应答式服务端上层可以不需要任何读写锁处理,数据可以不需要任何多余的拷贝。