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等工具, ...
随机推荐
- jquery 单行滚动、批量多行滚动、文字图片翻屏滚动效果代码
jquery单行滚动.批量多行滚动.文字图片翻屏滚动效果代码,需要的朋友可以参考下. 以下代码,运行后,需要刷新下,才能加载jquery,要不然看不到效果.一.单行滚动效果 <!DOCTYPE ...
- HDU 1698 Just a Hook 区间更新 lazy标记
lazy标记 #include <iostream> #include <cstdio> #include <cstring> #include <sstre ...
- flappy pig小游戏源码分析(3)——解剖util
这一节我们继续高歌猛进,如果对源码中有无论无何都理解不通的问题,欢迎和我交流,让我也学习一下,我的qq是372402487. 还是按照惯例看看我们的目录结构. 我们在前两节中已经分析了game.js, ...
- 【转载】shell中的特殊变量$
shell中的特殊变量:变量名含义$0shell或shell脚本的名字$*以一对双引号给出参数列表$@将各个参数分别加双引号返回$#参数的个数$_代表上一个命令的最后一个参数$$代表所在命令的PID$ ...
- TFS的使用
1.http://www.kwstu.com/ArticleView/kwstu_201462311500744
- CSS定义选择器
ID与类 层叠 分组 继承 上下文选择器 子类选择器 其他选择器 结构与注释 20.1 ID与类 选择器是用于控制页面设计的样式.即ID选择器何类选择器. 一直以来,许多开发人员经常将ID与类混淆,或 ...
- Uploadify 3.2 参数属性、事件、方法函数详解
一.属性 属性名称 默认值 说明 auto true 设置为true当选择文件后就直接上传了,为false需要点击上传按钮才上传 . buttonClass ” 按钮样式 buttonCursor ‘ ...
- vs2005升级到vs2010相关问题
1.项目编译失败,报 Resgen.exe 退出 ,错误代码2 处理方式: http://jingyan.baidu.com/article/90895e0fe80c6064ed6b0b6b.html ...
- 通过Wifi调试Android应用
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- 教你50招提升ASP.NET性能(十二):在生产环境,仔细考虑你需要记录哪些日志
(18)When in production, carefully consider what you need to log 招数18: 在生产环境,仔细考虑你需要记录哪些日志 Many peopl ...