没有合适的资源?快使用搜索试试~ 我知道了~
首页完成端口IOCP实现高并发服务器——一篇非常好的学习资源
资源详情
资源评论
资源推荐

转载自 hps://www.cnblogs.com/talenth/p/7068392.html
完成端口 IOCP 详解
由于篇幅原因,本文假设你已经熟悉了利用 进行 编程的基本原理,并且也熟练的掌握了
多线程编程技术,太基本的概念我这里就略过不提了,网上的资料应该遍地都是。
本文配套的示例源码下载地址
源地址已经失效了以下是源文件的一份
!"#$#%
&里面的代码包括 '(()**+'(()*,* 编写的完成端口服务器端和客户端的代码,还包括一个对服务
器端进行压力测试的客户端,都是经过我精心调试过,并且带有非常详尽的代码注释的。当然,作为教学代码,
为了能够使得代码结构清晰明了,我还是对代码有所简化,如果想要用于产品开发,最好还是需要自己再完善
一下,另外我的工程是用 )*,* 编写的,附带的 )**+ 工程不知道有没有问题,但是其中代码都是一样的,暂
未测试-
目录:
1
. 完成端口的优点
2
. 完成端口程序的运行演示
3
. 完成端口的相关概念
4
. 完成端口的基本流程
5
. 完成端口的使用详解
6
. 实际应用中应该要注意的地方
一. 完成端口的优点
,我想只要是写过或者想要写 模式网络服务器端的朋友,都应该或多或少的听过完成端口的大名吧,
完成端口会充分利用 . 内核来进行 ! 的调度,是用于 通信模式中性能最好的网络通信模型,没
有之一;甚至连和它性能接近的通信模型都没有。
)完成端口和其他网络通信方式最大的区别在哪里呢?
&,-首先,如果使用“同步”的方式来通信的话,这里说的同步的方式就是说所有的操作都在一个线程内顺
序执行完成,这么做缺点是很明显的:因为同步的通信操作会阻塞住来自同一个线程的任何其他操作,只有这
个操作完成了之后,后续的操作才可以完成;一个最明显的例子就是咱们在 /0 的界面代码中,直接使用阻塞
调用的代码,整个界面都会因此而阻塞住没有响应!所以我们不得不为每一个通信的 都要建立
一个线程,多麻烦?这不坑爹呢么?所以要写高性能的服务器程序,要求通信一定要是异步的。
&)-各位读者肯定知道,可以使用使用“同步通信&阻塞通信-(多线程”的方式来改善&,-的情况,那么好,
想一下,我们好不容易实现了让服务器端在每一个客户端连入之后,都要启动一个新的 和客户端进行
通信,有多少个客户端,就需要启动多少个线程,对吧;但是由于这些线程都是处于运行状态,所以系统不得
不在所有可运行的线程之间进行上下文的切换,我们自己是没啥感觉,但是 1 却痛苦不堪了,因为线程切换
是相当浪费 1 时间的,如果客户端的连入线程过多,这就会弄得 1 都忙着去切换线程了,根本没有多少
时间去执行线程体了,所以效率是非常低下的,承认坑爹了不?
1 / 26

&2-而微软提出完成端口模型的初衷,就是为了解决这种34 4 43的缺点的,它充分利
用内核对象的调度,只使用少量的几个线程来处理和客户端的所有通信,消除了无谓的线程上下文切换,最大
限度的提高了网络通信的性能。
2完成端口被广泛的应用于各个高性能服务器程序上,例如著名的 56如果你想要编写的服务器
端需要同时处理的并发客户端连接数量有数百上千个的话,那不用纠结了,就是它了。
二. 完成端口程序的运行演示
首先,我们先来看一下完成端口在笔者的 机上的运行表现,笔者的 配置如下:
大体就是 7)8**(,89$ 内存,我以这台 作为服务器,简单的进行了如下的测试,通过 生
成 2 万个并发线程同时连接至 : ,然后每个线程每隔 2 秒钟发送一次数据,一共发送 2 次,然后观察服务
器端的 1 和内存的占用情况。
如图 ) 所示,是客户端 2 万个并发线程发送共发送 ; 万条数据的 截图
2 / 26

图 2 是服务器端接收完毕 2 万个并发线程和每个线程的 2 份数据后的 截图
最关键是图 <,图 < 是服务器端在接收到 )+*** 个并发线程的时候,1 占用率的截图,使用的软件是
大名鼎鼎的 " ,因为相对来讲这个比自带的任务管理器要准确和精确一些。
3 / 26

我们可以发现一个令人惊讶的结果,采用了完成端口的 : 程序&蓝色横线所示-所占用的 1 才为
2+)=,整个运行过程中的峰值也没有超过 <=,是相当气定神闲的……哦,对了,这还是在 >? 环境下运
行的情况,如果采用 @ 方式执行,性能肯定还会更高一些,除此以外,在 1 上显示信息也很大成都上
影响了性能。
相反采用了多个并发线程的 程序&紫色横线所示-居然占用的 1 高达 ,,A2=,甚至超过了
: 程序的数倍……
其实无论是哪种网络操模型,对于内存占用都是差不多的,真正的差别就在于 1 的占用,其他的网络
模型都需要更多的 1 动力来支撑同样的连接数据。
虽然这远远算不上服务器极限压力测试,但是从中也可以看出来完成端口的实力,而且这种方式比纯粹
靠多线程的方式实现并发资源占用率要低得多。
三. 完成端口的相关概念
在开始编码之前,我们先来讨论一下和完成端口相关的一些概念,如果你没有耐心看完这段大段的文字
的话,也可以跳过这一节直接去看下下一节的具体实现部分,但是这一节中涉及到的基本概念你还是有必要了
解一下的,而且你也更能知道为什么有那么多的网络编程模式不用,非得要用这么又复杂又难以理解的完成端
口呢??也会坚定你继续学习下去的信心B#B
3.1 异步通信机制及其几种实现方式的比较
我们从前面的文字中了解到,高性能服务器程序使用异步通信机制是必须的。
4 / 26

而对于异步的概念,为了方便后面文字的理解,这里还是再次简单的描述一下:
异步通信就是在咱们与外部的 ! 设备进行打交道的时候,我们都知道外部设备的 ! 和 1 比起来简
直是龟速,比如硬盘读写、网络通信等等,我们没有必要在咱们自己的线程里面等待着 ! 操作完成再执行后
续的代码,而是将这个请求交给设备的驱动程序自己去处理,我们的线程可以继续做其他更重要的事情,大体
的流程如下图所示
我可以从图中看到一个很明显的并行操作的过程,而“同步”的通信方式是在进行网络操作的时候,主线程
就挂起了,主线程要等待网络操作完成之后,才能继续执行后续的代码,就是说要么执行主线程,要么执行网
络操作,是没法这样并行的;
C异步”方式无疑比 “阻塞模式(多线程”的方式效率要高的多,这也是前者为什么叫“异步”,后者为什么叫
“同步”的原因了,因为不需要等待网络操作完成再执行别的操作。
而在 . 中实现异步的机制同样有好几种,而这其中的区别,关键就在于图 , 中的最后一步“通知
应用程序处理网络数据”上了,因为实现操作系统调用设备驱动程序去接收数据的操作都是一样的,关键就是在
于如何去通知应用程序来拿数据。它们之间的具体区别我这里多讲几点,文字有点多,如果没兴趣深入研究的
朋友可以跳过下一面的这一段,不影响的-
&,-设备内核对象,使用设备内核对象来协调数据的发送请求和接收数据协调,也就是说通过设置设备内
核对象的状态,在设备接收数据完成后,马上触发这个内核对象,然后让接收数据的线程收到通知,但是这种
方式太原始了,接收数据的线程为了能够知道内核对象是否被触发了,还是得不停的挂起等待,这简直是根本
就没有用嘛,太低级了,有木有?所以在这里就略过不提了,各位读者要是没明白是怎么回事也不用深究了,
总之没有什么用。
&)-事件内核对象,利用事件内核对象来实现 ! 操作完成的通知,其实这种方式其实就是我以前写文章
的时候提到的《基于事件通知的重叠 ! 模型》,链接在这里,这种机制就先进得多,可以同时等待多个 ! 操
作的完成,实现真正的异步,但是缺点也是很明显的,既然用 .0 /?!D&-来等待 ": 的话,
就会受到 8< 个 ": 等待上限的限制,但是这可不是说我们只能处理来自于 8< 个客户端的 ,而是这
是属于在一个设备内核对象上等待的 8< 个事件内核对象,也就是说,我们在一个线程内,可以同时监控 8< 个
重叠 ! 操作的完成状态,当然我们同样可以使用多个线程的方式来满足无限多个重叠 ! 的需求,比如如果想
要支持 2 万个连接,就得需要 A** 多个线程…用起来太麻烦让人感觉不爽;
&2-使用 APC( Asynchronous Procedure Call,异步过程调用)来完成,这个也就是我以前在文章
里提到的《基于完成例程的重叠 ! 模型》,链接在这里,这种方式的好处就是在于摆脱了基于事件通知方式
5 / 26
剩余25页未读,继续阅读
















安全验证
文档复制为VIP权益,开通VIP直接复制

评论2