IOCP实现高并发以及与传统socke编程的对比
前言
传统socket编程中服务端一般为每一个客户端创建一个线程(一对一)。这样虽然可以使程序的结构简单明了并且方便对数据处理,但是这些都是建立在创建多个线程的基础上,也就是以牺牲线程为代价。一旦有大量数量了客户端连接服务端,我们的服务端需要创建很多线程,这样会造成很大的系统开销这显然是不能被我们所接受的。那么为了解决这个问题就必须采用一种方法令有限的线程去处理所有的客户端连接,利用windows的IOCP完成端口配合线程池就可以帮助我们完成这个操作。
IOCP实现高并发整体思路
IOCP实现高并发原理
我们先通过CreateIoCompletionPort()函数创建一个IOCP完成端口对象,然后每次有客户端连接时在调用CreateIoCompletionPort()函数将请求连接的客户端与IOCP完成端口对象绑定,并且设置完成键为客户端的socket。实际IOCP完成端口对象内部维护者一张设备列表,此列表记录着各个设备的句柄和对应的完成键,对于我们来说就是各个客户端的句柄和各个客户端的完成键(socket)。
然后我们会利用异步I/O函数WASRecv()接收客户端的数据包,当设备驱动程序将异步I/O完成后会这个完成的I/O请求追加到IOCP完成队列中。IOCP完成队列每一项都包含了已完成异步I/O的详细信息,如已传输字节数,完成键值,指向此次I/O的Overlapped结构的地址,错误码。线程池中等待队列中的线程会从IOCP完成队列中取出一项并将此项删除。
现在来看一下线程池是如何工作的,线程池中的线程都使用同一线程函数。首先线程池有三个队列:等待线程队列,已释放线程队列,已暂停线程队列。
我们一开始调用GetQueuedCompletionStatus时会让调用线程进入等待线程队列,当等待线程队列中的线程的GetQueuedCompletionStatus返回时会从IOCP队列中取出一项并将其从IOCP队列中删除,接着其线程就会从等待队列转移到已释放队列中。然后处理完之后为了继续接收客户端的数据包需要再次调用一下异步函数WASRecv(),这时线程会从已释放队列转移到已暂定队列中,这样做IOCP完成端口对象会发现此线程在已暂停队列中,所以会使IOCP完成队列中的其他项利用线程池中等待队列中的其他线程处理,而不会继续使用此线程。接着当此线程WASRecv()函数调用后其又会从已暂停队列回到已释放队列中,然后循环重新开始继续调用GetQueuedCompletionStatus,此线程又从已释放队列中移动到等待队列中。
相关函数
WSARecv/WSASend
WSARecv/WSASend与函数recv/send函数相对应,前者为异步函数,后者为同步函数。以WSARecv( )函数为例,此函数会产生一个异步I/O请求,然后立刻返回而此时并未真正收到数据包,等服务端接收到来自客户端的数据包异步I/O完成时会向IOCP对象的完成队列中添加一项,接着IOCP对象会从线程池中等待队列的线程中选择一个线程来进一步处理。CreateIoCompletionPort(HANDLE FileHandle, HANDLE ExistingCompletionPort, ULONG_PTR CompletionKey, DWORD NumberOfConcurrentThreads);
此函数为IOCP对象的创建或绑定函数,一开始我们需要借助此函数创建一个IOCP完成端口内核对象,然后每当一个客户端与服务端连接时我们都要将IOCP对象与此客户端的socket绑定。在客户端绑定IOCP完成端口对象时注意第三个参数CompletionKey,此参数为完成键。因为我们客户端的数据包最后都到数量受限的线程池中处理,为了区分是哪个客户端的数据包需要为每个不同的客户端指定不同的完成键,从而标志不同的客户端(通常用客户端的套接字作为完成键)。GetQueuedCompletionStatus()
哪个线程调用GetQueuedCompletionStatus()函数,其就会被IOCP完成对象认为是线程池中的一个线程。此函数从IOCP完成队列中取出一项,如果最后一个参数指定为INFINITE,则只有当异步I/O完成时也就是IOCP完成队列中有非空项时其会返回,否则一直等待。GetQueuedCompletionStatusEx()
此函数可以从IOCP完成队列中取出所有的项,这样我们可以避免开启多个线程并调用GetQueuedCompletionStatus()等待增加系统开销。PostQueuedCompletionStatus()
此函数可以向线程池中每一个工作线程都发送—个特殊的完成数据包,在退出程序的时候可以通过此函数来向线程池中的每一个线程发送一个特定的数据包使其线程安全退出
在利用IOCP完成端口对象时遇到的一些问题
- 因为WSARecv()在异步接受数据时会指定接受数据的内存,为了通过重叠结构传递这块内存,需要new[]出来这块内存放到堆中,所以记得delete[]。
因为重叠结构是IOCP完成对象与线程池中线程交互进一步传递来自客户端的数据的,所以这块内存也需要放到堆中new出来最后也要delete。
DWORD dwSize;
DWORD dwFlag = 0;
WSABUF stBuffer;
stBuffer.buf = new char[0x1000]();
stBuffer.len = 0x1000;
MYOVERLAPPED* lpMyOVERLAPPED = new MYOVERLAPPED;
memset(lpMyOVERLAPPED, 0, sizeof(MYOVERLAPPED));
lpMyOVERLAPPED->nTypr = TYPE_RECV; //表示发送一个收包请求任务
lpMyOVERLAPPED->pBuf = (BYTE *)stBuffer.buf; //使接收到的数据通过重叠结构传递
//异步接受消息(向任务队列投递一个接受请求)
WSARecv(
h,
&stBuffer, //缓冲区结构
1, //缓冲区数组数量
&dwSize,
&dwFlag,
&(lpMyOVERLAPPED->ol), //标准重叠结构
NULL);
- 因为我们客户端发送消息的形式一般是先发送包头,在发送包尾。所以 GetQueuedCompletionStatus()在从任务队列中取数据也是先获得包头数据再获得包尾数据。然后将其拼接成完整的包后处理。
- 我们在处理完一个包后需要往任务队列中再发送接收任务,等待下一次客户端的数据到达。这时我们需要在调用WSARecv()异步接受数据时需要重新指定新的内存给IOCP存放接受到的数据使用。所以需要重新new,至于new的大小取决于我们是接下来是接收包头还是接收包尾。接收包头就是new 包头大小,包尾就是new对应的包尾大小。(一个包分两次接收)。
注意不要采用每次new固定的大小内存来接收,这样会使GetQueuedCompletionStatus()一次获取不完包中数据从而进行多次调用,而在如果在获取包的最后的数据不足new的大小的话,其会把下一个包的数据一起放进来给我们带来不必要的麻烦。
DWORD dwSize;
DWORD dwFlag = 0;
WSABUF stBuffer;
if (pClient->stWrap.dwLength == 0) //如果刚收完包尾,继续收下一个包的包头
{
stBuffer.buf = new char[8]();
stBuffer.len = 8;
}
else //如果刚收完包头,则收对应大小的包尾
{
stBuffer.buf = new char[pClient->stWrap.dwLength]();
stBuffer.len = pClient->stWrap.dwLength;
}
memset(pMyOVERLAPPED, 0, sizeof(MYOVERLAPPED));
pMyOVERLAPPED->nTypr = TYPE_RECV; //表示发送一个收包请求任务
pMyOVERLAPPED->pBuf = (BYTE*)stBuffer.buf; //使接收到的数据通过重叠结构传递
//异步接受消息(向任务队列投递一个接受请求)
WSARecv(pClient->hSocketClient, &stBuffer, 1, &dwSize, &dwFlag, &(pMyOVERLAPPED->ol), NULL);
参考:《windows核心编程》
IOCP实现高并发以及与传统socke编程的对比的更多相关文章
- 配置开发支持高并发TCP连接的Linux应用程序全攻略
http://blog.chinaunix.net/uid-20733992-id-3447120.html http://blog.chinaunix.net/space.php?uid=16480 ...
- [转载] Linux下高并发socket最大连接数所受的各种限制
原文: http://mp.weixin.qq.com/s?__biz=MzAwNjMxNjQzNA==&mid=207772333&idx=1&sn=cfc8aadb422f ...
- Linux下高并发socket最大连接数所受的各种限制
http://blog.csdn.net/guowake/article/details/6615728 1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行 ...
- Linux配置支持高并发TCP连接(socket最大连接数)
Linux配置支持高并发TCP连接(socket最大连接数) Linux配置支持高并发TCP连接(socket最大连接数)及优化内核参数 2011-08-09 15:20:58| 分类:LNMP&a ...
- Linux下高并发socket最大连接数
http://soft.chinabyte.com/os/285/12349285.shtml (转载时原文内容做个修改) 1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是 ...
- Linux下高并发socket最大连接数各种限制的调优
1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每 ...
- Linux下高并发socket最大连接数所受的各种限制(转)
1.修改用户进程可打开文件数限制在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每个 ...
- 高并发TCP连接数目问题
linux可通过五元组唯一确定一个链接:源IP,源端口,目的IP,目的端口,传输层协议.而一个端口不允许被两个及以上进程占用(一个进程可同时占用多个端口),据此是否可以推测一台linux服务器最多可以 ...
- Linux下高并发socket最大连接数所受的各种限制(详解)
1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每 ...
随机推荐
- 最权威最简明的maven 使用教程
Maven是一个项目管理工具,它包含了一个项目对象模型 (Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Depen ...
- 前端学习 node 快速入门 系列 —— 服务端渲染
其他章节请看: 前端学习 node 快速入门 系列 服务端渲染 在简易版 Apache一文中,我们用 node 做了一个简单的服务器,能提供静态资源访问的能力. 对于真正的网站,页面中的数据应该来自服 ...
- Java基础API
API API概述 API (Application Programming Interface) :应用程序编程接口 java中的API指的就是 JDK 中提供的各种功能的 Java类,这些类将底层 ...
- golang 性能调优分析工具 pprof (上)
一.golang 程序性能调优 在 golang 程序中,有哪些内容需要调试优化? 一般常规内容: cpu:程序对cpu的使用情况 - 使用时长,占比等 内存:程序对cpu的使用情况 - 使用时长,占 ...
- 如何在CMDB中落地应用的概念?
如何在CMDB中落地应用的概念? 我们前面讲了应用是整个微服务架构体系下运维的核心,而CMDB又是整个运维平台的基石.今天我就讲讲在CMDB中如何落地应用这个核心概念,以及如何建立应用集群分组的思路. ...
- Shell prompt(PS1) 与 Carriage Return(CR) 的关系?-- Shell十三问<第二问>
Shell prompt(PS1) 与 Carriage Return(CR) 的关系?-- Shell十三问<第二问> 当你成功登录进一个文字界面之后,大部份情形下,你会在荧幕上看到一个 ...
- 如何从 dump 文件中提取出 C# 源代码?
一:背景 相信有很多朋友在遇到应用程序各种奇葩问题后,拿下来一个dump文件,辛辛苦苦分析了大半天,终于在某一个线程的调用栈上找到了一个可疑的方法,但 windbg 常常是以 汇编 的方式显示方法代码 ...
- 2-69.x的平方根
题目描述: 解题思路: 计算平方根可以依次通过自然数递增,来判断两者相乘是否为目标值,是一个有序的序列,因此考虑使用二分查找. 由于x=0和1时,就是其本身,单独拿出来.当x>1时,其平方根一定 ...
- ElasticSearch-03-远行、停止
在Windows下执行elasticsearch.bat 在Linux下运行./elasticsearch 指定集群名称和节点名称: ./elasticsearch --cluster.name my ...
- 假如kubernetes不支持docker了该怎么办
假如kubernetes不支持docker了该怎么办 从官网安装文档可以看到kubernetes支持一下几种: https://kubernetes.io/docs/setup/production- ...