【转】 IOCP内存管理

【转】 

 

IOCP内存管理
换上了log4cplus日志系统,记录发现有些情况下的io和完成key没有回归队列,多处释放又怕导致重复入队列。先转贴

两篇网上的文章:

IOCP中的socket错误和资源释放处理方法

前言:

错误处理和socket释放, 是IOCP编程中的一大难点. 本文试图就IOCP设计中经常遇到的这个难题展开论述并寻找其解决方案, 事实上, 文中所述的解决方式不仅仅适用于IOCP, 它同样适用于EPOLL等多种服务器编程的网络模型中, 前提是: 领会这种处理方式的实质.

正文:
在使用IOCP开发时, 大家经常遇到的一个难题是与socket相关的缓冲区释放不当带来的错误, 这种错误通常是由于多次对同一个指针执行了delete操作引起的. 比如, 当在执行wsasend或wsarecv返回了非pending的错误信息时, 我们就要对此错误进行处理, 通常情况下, 我们会想到执行这两步操作:
a. 释放此次操作使用的缓冲区数据(如果不释放可能造成内存泄漏);
b. 关闭当前操作所使用的socket.
另一方面, 我们可能也会在get函数(GetQueuedCompletionStatus)的处理中, 当get函数返回值为FALSE时也作这两步

相同的操作. 此时, 就会造成对同一缓冲区的重复释放, 问题由此产生.

解决的方法, 可以有这几种:
1. 对数据缓冲区使用引用计数机制;
2. 在clientsock的对象设计机制上使释放操作线性化.
关于这两种方法, 任何一种如果要详细说清, 可能篇幅都会比较长, 笔者并无耐心和精力将每一个细节都一一道来, 在

此仅选第2种方案的关键步骤和核心思想来与大家分享.

由前面对问题的描述可以看出, 造成多次释放的原因可能是在执行收发操作和GET函数返回值为FALSE时, 我们重复执行了释放操作. 很自然地, 我们会想到, 能不能把这两次释放合并成一次释放, 这样不就没问题了吗? yes, 这个思路是没问题的. 但要想让这个思路能变成现实, 需要在设计机制上对这个思路进行一定的支持.

首先, 我们假设, 是在get函数返回时统一进行相应的释放和关闭操作.

如果在执行wsasend操作时, 发生了非pending错误(io操作正在进行中), 而此时我们如果不释放资源, 那至少得让IOCP在GET返回时得知这个错误和发生错误时的缓冲区指针. 通知IOCP的方式, 是使用post函数(PostQueuedCompletionStatus)向IOCP抛一个特殊标志的消息, 这个特殊标志可以通过get函数的第二个参数, 即: 传送字节数来表示, 可以选择任何一个不可能出现的值, 比如任何一个跟它的初始值不相等的负数. 当然, 如果你通过单句柄数据或单IO数据来传递也是可以的. 而发生错误的这个缓冲区指针, 我们是必须要通过单句柄数据或单IO数据来传递的. 但是, 从整个缓冲区的管理机制上来说, 我不推荐这样的离散缓冲区机制, 我的建议是: 把收发缓冲区或数据队列与相应的clientsocket对象相绑定, 释放操作写在该对象的析构函数里, 这样当释放clientsocket对象时就释放了这些缓冲区.

ok, 这样一来, 在get函数里, 有三种情况需要执行释放逻辑:
1. get的返回值为FALSE;
2. 传送字节数为0;
3. 接收到刚才我们post的那个错误类型消息.

把释放操作全放在get函数里以后, 对释放操作的处理, 就比较统一了. 当然, 为了实现真正的线性化和元子化, 在释

放操作的最终执行逻辑上, 还需要对释放代码加锁以实现线程互斥(当然, 这是在你开了多个工作者线程的情况下).

(全文完)

这样一来,我便可以确定需要释放内存的地方了:
1. get的返回值为FALSE;
2. 传送字节数为0;
3.wsasend/wsarecv失败时(还不习惯上面文章所说post到工作线程处去处理)

   重要的是,如果重叠操作调用失败时(也就是说,返回值是SOCKET_ERROR,并且错误原因不是WSA_IO_PENDING),那么完成端口将不会收到任何完成通知。如果重叠操作调用成功,或者发生原因是WSA_IO_PENDING的错误时,完成端口将总是能够收到完成通知。

在我的系统中具体情况如下:
1.WSASend和WSARecv进行重叠调用时失败,即该socket已关闭,当场释放IO和句柄资源入队列。(因为重叠调用失败,完成端口将不会收到任何完成通知。)

2.WSASend重叠调用成功,但GetQueuedCompletionStatus返回失败。

1)因为cmwap和网关服务器连接后,该socket的关闭情况不稳定。常常是cmwap主动关闭了该连接,而完成端口没有收到socket断开的消息。若此时对该socket调用WSASend,GetQueuedCompletionStatus会返回WSASend失败的消息,错误是10054(远程主机强迫关闭了一个现有的连接)。
2)有时返回错误代码64(指定的网络不可用),这是因为socket被重置了。
3)等等.....

释放IO资源入队列。,并closesocket.

3.WSARecv重叠调用成功,但GetQueuedCompletionStatus返回失败。导致接收请求返回失败的原因比较多,比如:
1)投递的udp socket接收请求常常会失败返回,返回997错误:重叠 I/O 操作在进行中。
2)服务器主动关闭了对应的socket。如2所提到的closesocket,会导致所有投递在该socket上的IO请求返回。此时返回错误代码1236(由本地系统终止网络连接)。
释放IO资源入队列。,并closesocket.

 

 

http://hi.baidu.com/xujichao/blog/item/1019aef4c2c80968ddc47443.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值