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等工具, ...
随机推荐
- win7下代替IDM的下载工具
EagleGet 批量下载干刚刚的!!!!! 立马卸载IDM,哈哈哈 下载地址(免费软件) http://pan.baidu.com/s/1ntupiZJ
- Android_2015-04-07 Android中Intent的使用
1. 什么是Intent 1.1 Intent是Android程序中各个组件之间进行交互的一种方式,不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据. Intent一般可用于启动活动, ...
- MVC5中使用KinEditor
参考:http://www.cnblogs.com/weicong/archive/2012/03/31/2427608.html 第一步 将 KindEditor 的源文件添加到项目中,建议放到 / ...
- Petshop学习第三天
ASP.NET缓存 ASP.NET充分利用缓存机制,通过某种方法,将系统需要的数据对象.Web页面存储在内存中,使得Web站点需要这些数据时,不经过繁琐的数据库连接.查询和复杂的逻辑运算,就可以触手可 ...
- maven 本地仓库的设置
设置方式一: 安装好maven后,在maven安装目录的conf文件夹下有一个settings.xml文件,该文件就是用来配置maven的一些常用参数 %MAVEN% / conf / setting ...
- c功能实战
1,linux C连接ftp实现简单的上传下载; libcurl/libftp/busybox; oracle查看用户信息 1. 查询oracle中所有用户信息 select * from dba_u ...
- Django model中 双向关联问题,求帮助
Django model中 双向关联问题,求帮助 - 开源中国社区 Django model中 双向关联问题,求帮助
- ubuntu完全卸载一个软件
今天卸载一个软件,老是有配置残留,网上找到了解决方案: 查看已安装的软件: dpkg -l |grep 软件名 找到一大堆相关的包,然后卸载核心的包: sudo apt-get remove --pu ...
- 射频识别技术漫谈(2)——国际标准【worldsing 笔记】
如果你只是智能卡的用户,通常可以不必关注国际标准,但作为智能卡的专业开发人员,则至少也要对相关标准有所了解.国际标准一般都是西方人制定的,原版都是英文的,而所谓中文版往往是对原版的直译,许多情况下并未 ...
- js为表格添加行和列
<table id="studentTable" align="center" border="1px;" cellpadding=& ...
