对IOCP的讨论

2024-01-06 01:38
文章标签 讨论 iocp

本文主要是介绍对IOCP的讨论,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在之前的一次客户项目中,由于采用的是别人的方案, 服务器 在运行几天不等的时间,会出现崩溃的现象,由于后来的一个项目上来了,也没有时间去深究这个问题。这里对客户表示一下道歉。

这段时间,由于对年前书籍的撰写并没有达到我的预期目标,开始整理时间,慢慢的写这本书,或者可以说是慎重的写这本书,为什么这么说呢。

在 我们这个大环境里面,太多太多的“牛人” 总是不屑别人的东西,当然我很佩服你们的技术,说实话,可是我并不欣赏你们的一些道德。当然我只是说一部分人啊。我这里所指的事情,是什么呢?偶尔有一些 人来浏览我的博客,很感谢你们的关注,也很感谢你们的留言,有些文章是我早期所写,可能里面的内容过于简单,但是我想仅仅是给新手一点微薄的帮助,并没有 妨碍您什么吧?没有必要说一些非常不友好的话来刺激一下作者,或者您认为这样能给你带来多高的威望,或者那些荣耀,我当然会很支持您继续对我喷。不说这些 没有必要的。

当然整理来说,非常感谢 unsigned,hurryboylqs,muroachanf,blastzgd 还有 sodmeelssan 几位在我理解IOCP中给予的帮助,非常感谢这些前辈和同辈。尤其是elssan兄长,和你的交流让我收获不少,还有大宝兄长,祝愿你的游戏可以运作的很成功。

开篇吧:

1:先让我们看一下OVERLAPPED结构,这个将非常有利于我们的理解IOCP的机制。
view plain print ?
  1. typedef   struct  _OVERLAPPED {  
  2.   ULONG_PTR  Internal;   
  3.   ULONG_PTR  InternalHigh;   
  4.   DWORD  Offset;   
  5.   DWORD  OffsetHigh;   
  6.   HANDLE  hEvent;   
  7. } OVERLAPPED;  


上面我的结构中,大家一定要关注这个 HANDLE hEvent;数据类型,我先把我的猜测结果说一下。
IOCP是一个非常典型的Queue队列模型,每当我们在一个Socket对象上面,当然更确切的说应该是Handle上面Post一次WSARecv或者一次WSASend之后,IOCP将把这次操作直接放入Queue队列。

第一次CreateIoCompletionPort的时候,我的理解相当于创建了一个IOCP队列,以及该队列的辅助对象,包含一个锁(甚至多个锁)。

当第二次调用CreateIoCompletionPort绑定CompletionKey 的时候,相当于把这个Key作为IOCP关注的事件。

如前面所说, Post一次WSARecv或者一次WSASend之后,IOCP将把这次操作直接放入Queue队列。而同时相当于创建了一个hEvent,并且设置该hEvent为空,后面我们只需要使用线程去等待事件被置信。 这个时候,我们应该做的有什么呢?

当然GetQueuedCompletionStatus是去等待某个OVERLAPPED结构的hEvent被触发而已。如果多个线程的话,只需要在触发出Queue队列的时候互斥一下就可以了,由于Queue队列的特殊性,典型的先进先出,保证了数据的完整序数。

2: 上面的一段话如果您还不理解的话,我们换个角度来说吧。我们能够从之前的代码中看到,大部分是一个业务简单的ECHO Server,在实际的应用中,并没有实际的大意义,而对于实际的服务器来说,大部分需要将数据做处理后,然后来发给客户端,如果仅仅在现有的提供代码的 Server中修改,自然并不是什么好的建议。而且经常会出现奇怪的现象,笔者我也遇到过。所以下面我把最近的一些体会写一下。

在讨论的帖子中,unsigned道出了一个关键的地方。
引用

另 一个Overlapped结构则命名为PerIO*(在GetQueuedCompletionStatus当中由第四个参数返回),即,它在每一次 I/O操作当中都是唯一的。而我前面提到的就是指这个PerHandle*(暂定为Context)何时释放的问题,如果你有一个WSARecv关联其 中,那么你释放了,其它的WSASend将无法再使用该结构指针(此时已经是野指针),但是由于在多线程系统当中,这只是一个瞬息的时间差,根本就无法判 断(如果使用临界区确实可以达到同步的目的,但是对于“高性能”的应用,显得得不尝失),之所以很多人不能把完成端口写好,问题也就出在这里,基本上这可 以被视为IOCP的一个关键。


这点我同时在看国外的一些文献的时候,有一些模糊的概念,然后unsigned提出之后,有点具体的想法了,开始代码测试一下,才正式的验证的确是如此,我想这对于理解IOCP有深一层的意义。

也 就是对于线程外,比如单独的线程处理收到的数据,然后回发的时候,我们应该使用一个新的PerIOData,我想通过第一点的分析,大家应该有所理解,为 什么要新一个PerIOData呢,回到最先的OVERLAPPED结构,我们注意hEvent,如果我们再次使用同一个PerIOData,必然将这个 hEvent重新设置,这将导致不可预期的结果,我想大部分的文章都没有提及这块,或许是他们疏忽了。这也就是如果我们要在单独的线程处理数据时候需要考 虑的问题, ***必须使用一个新的PerIOData***.

3:当然由于这些新的PerIOData,就将导致一些相关的问题了,就是释放资源的问题,何时释放?

   
Tags: 服务器 , iocp | 引用(0)
fangle
2009/08/23 03:57
理解是肤浅的
脸皮是厚厚的

就这点水平,就急着卖钱,嘿嘿
huzhangyou2002 Email Homepage
2008/07/09 14:06
其实IOCP的优势就是可以直接返回指针,而如果还去做遍历,就是完全丢失了IOCP特性,根本就是浪费,我的感觉。
对你说的两个合到一起我没有测试过,感觉会有资源的浪费,所以两个分开来说是更合适的,当然我并没有实际测试过,没有发言权,如果楠楠兄可以有一些数据比较结果出来,可能更加有说服力。

现在我反而比较倾向于临时用,当然这个临时只是针对性的,本身这个资源已经在启动的时候一次性创建了很多,等待需要直接从队列中获取,GQCS返回,再返回队列。楠楠兄有没有什么更好地方法?
楠楠
2008/07/09 13:47
前面说IOCP的投递, 返回, per-I/O, 和 per-Handle都是投递进队列, 最后返回回来, 从这一点讲差不多. 问题是一先一后, 这个先后,其实应该是从acceptEx为界.  per-Handle的socket时二次绑定KEY的, 一般这里为上下文. 而per-I/O是在acceptEx之前就绑定的.  而Get的时候, 意思是都会返回. 多了一个可选择的上下文结构. 当然, 其实低层如胡兄所言, 我也认为是per-I/O的事件状态返回. 不过是多了一个上下文. 所以很有一些人主张再去遍历上下文队列, 是十分不明智的. 这里可以直接返回指针, 为什么还要遍历呢?
      另外就是, 这两个结构其实是可以合并成到一个上下文结构中的. 实现中,我也是这么做的. 方便管理. 所以说是非常灵活的, 另外, buffer, 到底是在I/O中,还是handle中呢. handle是不可能的, 因为handle在后. 但是不是一定在i/o结构中呢. 不一定, 可以合并在上下文中, 也可以是分离的, 单独的. 所以上下文中的OVERLAPPED要么 可以把收发设计分开, 或者用临时的也可以呀.
      总之, 理解了这两个结构, 才能有点进入IOCP的深层次,也就明白了释放等一系列问题, 大宝等一些高手, 其实也提到这些问题, 只是需要有深度掌握的才能理解的.
huzhangyou2002 Email Homepage
2008/07/08 18:36
非常感谢 楠楠兄的详细讲解 让这篇文章更加有可读性,而且将其中的几个关键问题更加彻底清晰起来,说实话,自己在研究IOCP这么长时间,实在觉得没有那篇文章将HEVENT那个地 方讲的很好了,也很多次自己误解了IOCP,以至于对客户的项目没有处理好,当然在经历一些失败之后,自己在究其根源的时候才发现并不像想象的那么复杂。

当 然楠楠兄提到的Per-I/O新的概念,其实我的设计理念是这样的,在一开始就已经创建了很多空的Per-I/O,在需要的时候我取出来,而不需要删除, 而不需要了或者GQCS里面返回来表示用完了,我再返回队列,这样避免了申请和删除的操作,相对资源的管理会更加合理,当然这个思想是当初从Cker兄那 里请教而来的。

这里非常感谢楠楠兄的指点,也希望可以留下联系方式,以后继续交流
楠楠
2008/07/08 16:29
胡兄讲了一些问题,而且实际情况确实如此,对Event, Queue的认识也如老兄所言。
      另外我想补充一点,per-I/O 和per-Handle,我对这两个概念十分反感,因为它误
      导了非常非常多学习IOCP的同行,这两个结构设计目的是什么,为什么有这两个结构,
      可不可以抛弃,或者合并,同时和完成端口有什么联系,因此导致的设计和多线程效率
      及释放问题,能回答出来的,不多。
          我想高手往往都是喜欢藏私的。而为了研究IOCP,我读了非常非常多的代码。不同的
      结构,思路,能导致IOCP变得异常灵活和异常复杂。无形中增加了学习难度。
          per-I/O数据。它包含了在套节字上处理I/O操作的必要信息
          per-Handle数据。它包含了一个套节字的信息
          这是一些书本的解释, 讲的没错,但不深入。我强调一点,per-I/O 就是要包含OVERLAPPED
      结构, per-Handle面对的,就是一个socket。OVERLAPPED如胡兄所讲,它是投递用的。要进
      IOCP队列的。另外我再强调二点,投递,返回。如果你不了解投递,返回,你压根就不懂IOCP,
      它就象WIN消息队列一样,用户投递消息,最终由OS处理消息,再回调你。IOCP就这么回事。
      你投递消息,IOCP进队列,处理再返回给你(接收到的消息,发送完成的数据(未完成,完成))。
      另外,我再讲 per-I/O , per-Handle。再说简点一点,它就是二数据结构,没啥。区别如同胡兄所讲。
      per-I/O 中有Event。 而per-Handle往往是一个socket. 我们要记住的一点就是,它就象俄罗斯轮盘
      一样,转了一把之后,东西又回到你手上了。从这点上讲区别:handle要生得晚一点。为啥自己想想。
      handle使用一定比 per-I/O使用的晚。我讲分开的情况,才论使用早晚,其实它们是可以合并的。
          另外胡兄讲 per-I/O要一个新的,虽然说程序上没错,但道理上有些牵强,原因我在前面讲过,
      它只是OVERLAPPED而已,每次调用清空,或者合理的逻辑,都可以避免这种情况,另外就是一开始设计
      时收发就是分开的这种笨方法,或者用临时的 OVERLAPPED都能达到这种效果。所以IOCP呀IOCP,
      per-I/O 和per-Handle结构让多少人止步不前。
          我的口水就是多,下次吧,下次再聊。要下班了。

这篇关于对IOCP的讨论的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/574816

相关文章

MySQL中闪回功能的方案讨论及实现

《MySQL中闪回功能的方案讨论及实现》Oracle有一个闪回(flashback)功能,能够用户恢复误操作的数据,这篇文章主要来和大家讨论一下MySQL中支持闪回功能的方案,有需要的可以了解下... 目录1、 闪回的目标2、 无米无炊一3、 无米无炊二4、 演示5、小结oracle有一个闪回(flashb

聊聊分布式,再讨论分布式解决方案

前言 最近很久没有写博客了,一方面是因为公司事情最近比较忙,另外一方面是因为在进行 CAP 的下一阶段的开发工作,不过目前已经告一段落了。 接下来还是开始我们今天的话题,说说分布式事务,或者说是我眼中的分布式事务,因为每个人可能对其的理解都不一样。 分布式事务是企业集成中的一个技术难点,也是每一个分布式系统架构中都会涉及到的一个东西,特别是在微服务架构中,几乎可以说是无法避免,本文就分布式事

如何利用ChatGPT提升学术论文讨论部分的撰写质量和效率

大家好,感谢关注。我是七哥,一个在高校里不务正业,折腾学术科研AI实操的学术人。关于使用ChatGPT等AI学术科研的相关问题可以和作者七哥(yida985)交流,多多交流,相互成就,共同进步,为大家带来最酷最有效的智能AI学术科研写作攻略。经过数月爆肝,终于完成学术AI使用教程,估计也有个50万字的详细操作指南。跟着一步一步操作,借助ChatGPT做学术、干科研、写论文、课题申报都变得超简单。欢

图形API学习工程(12):讨论当前工程里同步CPU与GPU的方式

工程GIT地址:https://gitee.com/yaksue/yaksue-graphics 简单讨论CPU和GPU间的交互 《DX12龙书》在【4.2 CPU与GPU间的交互】章节中讨论了这个问题,简单来说: 为了最佳性能,CPU和GPU这两种处理器应该尽量同时工作,少“同步”。因为“同步”意味着一种处理器以空闲状态等待另一种处理器,即它破坏了“并行”。 但有时,又不得不进行二者的同步

讨论“get”和“post”安全性

get”安全,还是“post”安全?这或许是大家总结两者必须要分析的内容,因为这涉及到我们将内容从浏览器传送到服务器的安全性,选择不当将会带来巨大的不安全因素,从而可能带来巨大的损失。这篇博客,我将阐述一下,当然更多的还是希望各位大神发表一下见解,讨论一下下!             首先,我们来看一下两者最基本的区别: GET请求通过URL(请求行)提交数据,在URL中可以看

Android 疑难问题讨论及面试题

https://github.com/android-cn/android-discuss/issues?page=1&q=is%3Aissue+is%3Aopen

讨论运维监控工具的普及程度

在讨论运维监控工具的普及程度时,加入PIGOSS BSM产品的分析是非常有意义的,因为PIGOSS BSM是一款在中国市场具有一定影响力的运维监控工具。 PIGOSS BSM运维监控工具是一款综合性的IT运维监控解决方案,它能够对多层次的IT资源进行监测,包括但不限于性能监测、事件管理、报表管理等功能模块。PIGOSS BSM的一个独特之处在于其拓扑关联配置工具,这使得用户可以根据自身的I

8种进行简单线性回归的方法分析与讨论

以下是八种进行简单线性回归的方法及其分析与讨论: 二乘法(OLS): 分析:通过化预测值与实际值之间的平方误差来估计回归系数。 讨论:简单直观,适用于大多数线性回归问题。但对于数据中存在异常值或噪声时,可能不够鲁棒。 梯度下降法: 分析:通过迭代优化算法调整回归系数,以化损失函数。 讨论:适用于大规模数据集和复杂模型,但需要选择合适的学习率,并可能需要较长的训练时间。 正规方程法:

在Spring框架中,如何实现依赖注入?请列举几种注入方式。请解释Spring Boot的自动配置特性,并讨论其如何简化Web应用开发。

在Spring框架中,如何实现依赖注入?请列举几种注入方式。 在Spring框架中,依赖注入(Dependency Injection,简称DI)是一种实现控制反转(IoC,Inversion of Control)的技术。依赖注入允许对象在创建时不直接依赖于它们的依赖项,而是在运行时由外部实体(如Spring容器)将这些依赖项注入到对象中。这有助于减少代码间的耦合,提高模块的可重用性和可测试性

请解释Java中的装箱拆箱操作对性能的影响,并讨论其最佳实践。什么是Java中的值传递和引用传递?它们在函数调用中的表现有何不同?

请解释Java中的装箱拆箱操作对性能的影响,并讨论其最佳实践。 在Java中,装箱(Boxing)和拆箱(Unboxing)操作是Java自动类型转换机制的一部分,主要用于基本数据类型(如int, double, char等)和它们对应的包装类(如Integer, Double, Character等)之间的转换。这种机制使得基本数据类型可以像对象一样被操作,但同时也带来了性能上的开销。 装箱