Windows下性能最好的I/O模型——完成端口
I/O模型——完成端口
设计目的:
常见的网络通信分为两种:同步和异步。
在同步通信中,每一次接受数据都会导致主线程的挂起,从而阻塞住了其他操作。为了解决这一问题,我们通常会采取同步通信+多线程的策略,即为每一个连入的Socket分配一个线程。然而随着连入的Socket的数量的增加,线程的数量也在增加,这样CPU则需要不停地进行线程的切换,因此难以成为高性能的服务器程序。
异步通信则可以把接收数据这一操作交给内核,即在内核接收数据的时候,主线程可以不用被阻塞并且继续执行其他操作,而一旦接收数据完成以后,再由内核通知主线程。而如何通知主线程是一个关键,不同的异步通信策略有着不同的通知方式。
在这样的情况下,完成端口这一I/O模型被提出,成为目前Windows下性能最好的I/O模型之一。
实现原理:
首先根据CPU数量开好线程,当有用户请求的时候,把这些请求加入一个特定的消息队列中,而事先开好的线程则会排队从这个消息队列中获取请求并作出处理。完成端口正是指这一消息队列.
基本流程:

主要的API:
- 创建完成端口
HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0 );
HANDLE WINAPI CreateIoCompletionPort(
_in_ HANDLE FileHandle,
// Socket的句柄,置为INVALID_HANDLE_VALUE表示创建一个没有和任何HANDLE有关系的完成端口
_in_opt HANDLE ExistingCompletionPort,
// NULL表示新建一个完成端口
_in_ ULONG_PTR CompletionKey,
// 完成键,创建完成端口时置为0
_in_ DWORD NumberOfConcurrentThreads
// 完成端口并发线程的数量,置0表示有多少个CPU就开多少个线程
);
- 创建监听Socket
初始化Socket库...
...
listenSoc = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
...
绑定端口,并监听...
- 将监听的Socket绑定到完成端口上,这里同样使用
HANDLE WINAPI CreateIoCompletionPort(...)这一API.
CreateIoCompletionPort(listenSoc, iocp, CompKey, 0);
HANDLE WINAPI CreateIoCompletionPort(
_in_ HANDLE FileHandle,
// 监听Socket的句柄
_in_opt HANDLE ExistingCompletionPort,
// 刚才创建的完成端口
_in_ ULONG_PTR CompletionKey,
// 完成键,我们在绑定的同时为其分配一段内存空间,以存储与这一Socket相关的信息,当网络操作完成的时候,我们可以根据这段内存空间里面的信息分辨这是哪一个Socket
_in_ DWORD NumberOfConcurrentThreads
// 完成端口并发线程的数量,置0表示有多少个CPU就开多少个线程
);
- 在监听端口上投递AcceptEX请求
AcceptEX与传统的Accept有三个主要不同点:
- AcceptEX采取异步方式,可以同时投递多个请求,而Accept采取阻塞的方式,依次只能处理一个请求。
- AcceptEX会事先准备好Socket,当用户请求连入的时候直接使用这一新的Socket,避免临时创建Socket。
- AcceptEX接受连入请求的同时,我们可以附加一些数据,这样我们就可以在接受用户连入的同时,接受来自用户的第一组数据。
BOOL AcceptEx (
SOCKET sListenSocket, // 监听Socket
SOCKET sAcceptSocket, // 事先准备好给新用户的Socket
PVOID lpOutputBuffer, // 接受缓冲区
DWORD dwReceiveDataLength, // 用于存放用户第一组数据的空间大小
DWORD dwLocalAddressLength, // 本地地址的空间大小
DWORD dwRemoteAddressLength, // 客户端地址的空间大小
LPDWORD lpdwBytesReceived,
LPOVERLAPPED lpOverlapped
// 重叠结构,每一个网络操作都会对应一个重叠结构,相当于网络操作的ID
);
- 投递接受数据请求
int WSARecv(
SOCKET s, // 接受数据的Socket
LPWSABUF lpBuffers, // 接收缓冲区
DWORD dwBufferCount, // 置为1
LPDWORD lpNumberOfBytesRecvd, // 所接收到的字节数
LPDWORD lpFlags, // 置为0
LPWSAOVERLAPPED lpOverlapped, // 这个Socket对应的重叠结构
NULL
);
- 解析AcceptEX接收到的数据
AcceptEX缓冲区里面保存着本地地址,客户端地址以及客户端发来的第一组数据,因此我们需要使用GetAcceptExSockAddrs()来解析这些数据.
void GetAcceptExSockaddrs(
_In_ PVOID lpOutputBuffer,
// AcceptEX中的缓冲区
_In_ DWORD dwReceiveDataLength,
// 用户第一组数据的空间大小
_In_ DWORD dwLocalAddressLength,
// 本地地址的空间大小
_In_ DWORD dwRemoteAddressLength,
// 客户端地址的空间大小
_Out_ LPSOCKADDR *LocalSockaddr,
// 本地地址
_Out_ LPINT LocalSockaddrLength,
// 实际本地地址的空间大小
_Out_ LPSOCKADDR *RemoteSockaddr,
// 客户端地址
_Out_ LPINT RemoteSockaddrLength
// 实际客户端地址的大小
);
参考: 1. 完成端口(CompletionPort)详解 - 手把手教你玩转网络编程系列之三
2. Overlapped模型深入分析
Windows下性能最好的I/O模型——完成端口的更多相关文章
- windows下的套接字IO模型
一般情况下,IO操作的行为受两种因素的影响: IO操作对象的类型(阻塞还是非阻塞) 获取IO操作结果的方式(同步还是异步). 同步就是指操作的发起和操作结果的获取由调用者完成. 异步指操作发起由调用方 ...
- 关于获取Windows下性能参数的总结
Windows下特定进程或者所有进程的CPU.物理内存.虚拟内存等性能参数的获取方法小结,包括如何在MFC中以及如何使用C#语言来获取参数. VC API:GlobalMemoryStatus 获取全 ...
- 获取Windows下某进程监听的TCP/UDP端口
1.在Windows下用CMD netstat命令可以获得当前进程监听端口号的信息,如netstat -ano可以看到IP.port.状态和监听的PID. 那么可以执行CMD这个进程得到监听的端口号信 ...
- windows下使用远程工具登录虚拟机上的Linux、访问虚拟机上的服务 、端口转发、win7 telnet登陆虚拟机
首先要清楚virtual box如何设置端口转发: 一篇文章: 如何使用VirtualBox进行端口转发 由于默认的方式是用NAT来做虚拟机网络的,因此如果从外网想访问虚拟机的应用会比较麻烦.以前一直 ...
- 关于 Poco::TCPServer框架 (windows 下使用的是 select模型) 学习笔记.
说明 为何要写这篇文章 ,之前看过阿二的梦想船的<Poco::TCPServer框架解析> http://www.cppblog.com/richbirdandy/archive/2010 ...
- 比较windows下的5种IO模型
看到一个很有意思的解释: 老陈有一个在外地工作的女儿,不能经常回来,老陈和她通过信件联系.他们的信会被邮递员投递到他们的信箱里. 这和Socket模型非常类似.下面我就以老陈接收信件为例讲解Socke ...
- 机器学习模型从windows下 spring上传到预发布会导致模型不可加载
1.通过上传到redis,程序通过redis拉取模型,解决问题. 2.问题原因初步思考为windows下模型文件上传到 linux导致,待继续跟进查找.
- windows下的IO模型之异步选择(WSAAsyncSelect)模型
异步选择(WSAAsyncSelect)模型是一个有用的异步I/O 模型.其核心函数是WSAAsyncSelect,该函数是非阻塞的 (关于异步io的理解详情可以看:http://www.cnblog ...
- 记一次虚拟化环境下Windows IO性能的解析
前言随着云计算技术与服务的发展和进步,越来越多的客户选择将业务部署到云端.但由于引入了虚拟化层,在业务部署过程中经常会遇到IO问题,通常也不易调试.本文主要介绍利用perf.systemtap等工具, ...
随机推荐
- 屏蔽同步(JAVA)
以全球气候预测程序为例.这些程序通过将地球分为许多单元,在每个循环中,每个单元的计算都是隔离进行的,直到这些值趋于稳定,然后相邻单元之间就会交换一些数据.所以,从本质上讲,在每个循环中各个线程都必须等 ...
- JS 框架之我感
对于一些js框架在我看来,都是将前端的表现动态化,即用动态js把html加载到页面上,如angularJS的MVVM开发模式(已接触),ReactJS的View层组件化(学习中),还有一些只听过没见过 ...
- KindEditor 4.1.10 (2013-11-23)首行空格不能显示在编辑器内
KindEditor版本: KindEditor 4.1.10 (2013-11-23) 一.BUG再现步骤: 1.文章前面插入二个全角空格作为缩进,因为并非所有段落都有缩进故不采用 CSS 的 te ...
- 使用SVN服务器管理源码
最近在学习使用SVN管理自己的项目文件,正好有好的文章就拿来标记一下,正所谓: 站在巨人的肩膀上 天下知识为我所用 转载两篇关于使用SVN管理源码的文章. 使用SVN进行源码管理(上):http: ...
- [iOS基础控件 - 6.7] 微博展示 使用代码自定义TableCell(动态尺寸)
A.需求 1.类似于微博内容的展示 2.头像 3.名字 4.会员标志 5.内容 6.分割线 7.配图(可选,可有可无) code source: https://github.com/hellov ...
- define
define('player',['videoplay'],function(videoplay){ var wrap_player = $('#live_SWF'), obj_player = '' ...
- 用EPOLL进行压力测试
在以前的博客中提到的一个服务端,在以前压力测试的过程中,发现单核CPU最多能达到1000TPS 还以为是服务端性能不够好,所以一直想着怎么去优化它. 但优化的思路明显不多,所以就考虑换一种压力测试的方 ...
- 【AwayPhysics学习笔记】:Away3D物理引擎的简介与使用
首先我们要了解的是AwayPhysics这个物理引擎并不是重头开始写的新物理引擎,而是使用Flascc技术把一个已经很成熟的Bullet物理引擎引入到了Flash中,同时为了让as3可以使用这个C++ ...
- 【Away3D代码解读】(三):渲染核心流程(渲染)
还是老样子,我们还是需要先简略的看一下View3D中render方法的渲染代码,已添加注释: //如果使用了 Filter3D 的话会判断是否需要渲染深度图, 如果需要的话会在实际渲染之前先渲染深度图 ...
- Oracle- 查询误删数据
使用flashback table能恢复误删数据. flashback table CONTAINER_CONTENT to timestamp to_timestamp('2010-06-30 22 ...
