当前位置:首页 > Windows程序 > 正文

Windows完成端口与Linux epoll技术简介

2021-05-25 Windows程序

WINDOWS完成端口编程
1、基本概念
2、WINDOWS完成端口的特点
3、完成端口(Completion Ports )相关数据结构和创建
4、完成端口线程的工作原理
5、Windows完成端口的实例代码
Linux的EPoll模型
1、为什么select落后
2、内核中提高I/O性能的新方法epoll
3、epoll的优点
4、epoll的工作模式 
5、epoll的使用方法
6、Linux下EPOll编程实例
总结

WINDOWS完成端口编程
        摘要:开发网络程序从来都不是一件容易的事情,尽管只需要遵守很少的一些规则;创建socket,发起连接,接受连接,发送和接受数据。真正的困难在于:让你的程序可以适应从单单一个连接到几千个连接乃至于上万个连接。利用Windows平台完成端口进行重叠I/O的技术和Linux在2.6版本的内核中引入的EPOll技术,可以很方便在在在Windows和Linux平台上开发出支持大量连接的网络服务程序。本文介绍在Windows和Linux平台上使用的完成端口EPoll模型开发的基本原理,同时给出实际的例子。本文主要关注C/S结构的服务器端程序,因为一般来说,开发一个大容量,具可扩展性的winsock程序一般就是指服务程序。

1、基本概念
      设备---windows操作系统上允许通信的任何东西,比如文件、目录、串行口、并行口、邮件槽、命名管道、无名管道、套接字、控制台、逻辑磁盘、物理 磁盘等。绝大多数与设备打交道的函数都是CreateFile/ReadFile/WriteFile等。所以我们不能看到**File函数就只想到文件 设备。与设备通信有两种方式,同步方式和异步方式。同步方式下,当调用ReadFile函数时,函数会等待系统执行完所要求的工作,然后才返回;异步方式 下,ReadFile这类函数会直接返回,系统自己去完成对设备的操作,然后以某种方式通知完成操作。
重叠I/O----顾名思义,当你调用了某 个函数(比如ReadFile)就立刻返回做自己的其他动作的时候,同时系统也在对I/0设备进行你要求的操作,在这段时间内你的程序和系统的内部动作是 重叠的,因此有更好的性能。所以,重叠I/O是用于异步方式下使用I/O设备的。 重叠I/O需要使用的一个非常重要的数据结构OVERLAPPED。

2、WINDOWS完成端口的特点
    Win32重叠I/O(Overlapped  I/O)机制允许发起一个操作,然后在操作完成之后接受到信息。对于那种需要很长时间才能完成的操作来说,重叠IO机制尤其有用,因为发起重叠操作的线程 在重叠请求发出后就可以自由的做别的事情了。在WinNT和Win2000上,提供的真正的可扩展的I/O模型就是使用完成端口(Completion Port)的重叠I/O.完成端口---是一种WINDOWS内核对象。完成端口用于异步方式的重叠I/0情况下,当然重叠I/O不一定非使用完成端口不可,还有设备内核对象、事件对象、告警I/0等。但是完成端口内 部提供了线程池的管理,可以避免反复创建线程的开销,同时可以根据CPU的个数灵活的决定线程个数,而且可以让减少线程调度的次数从而提高性能其实类似于 WSAAsyncSelect和select函数的机制更容易兼容Unix,但是难以实现我们想要的“扩展性”。而且windows的完成端口机制在操作系统内部已经作了优化,提供了更高的效率。所以,我们选择完成端口开始我们的服务器程序的开发。
1、发起操作不一定完成,系统会在完成的时候通知你,通过用户在完成端口上的等待,处理操作的结果。所以要有检查完成端口,取操作结果的线程。在完成端口上守候的线程系统有优化,除非在执行的线程阻塞,不会有新的线程被激活,以此来减少线程切换造成的性能代价。所以如果程序中没有太多的阻塞操作,没有必要启动太多的线程,CPU数量的两倍,一般这样来启动线程。
2、操作与相关数据的绑定方式:在提交数据的时候用户对数据打相应的标记,记录操作的类型,在用户处理操作结果的时候,通过检查自己打的标记和系统的操作结果进行相应的处理。 
3、 操作返回的方式:一般操作完成后要通知程序进行后续处理。但写操作可以不通知用户,此时如果用户写操作不能马上完成,写操作的相关数据会被暂存到到非交换 缓冲区中,在操作完成的时候,系统会自动释放缓冲区。此时发起完写操作,使用的内存就可以释放了。此时如果占用非交换缓冲太多会使系统停止响应。

3、完成端口(Completion Ports )相关数据结构和创建
    其实可以把完成端口看成系统维护的一个队列,操作系统把重叠IO操作完成的事件通知放到该队列里,由于是暴露 “操作完成”的事件通知,所以命名为“完成端口”(COmpletion Ports)。一个socket被创建后,可以在任何时刻和一个完成端口联系起来。
完成端口相关最重要的是OVERLAPPED数据结构
typedef struct _OVERLAPPED { 
    ULONG_PTR Internal;//被系统内部赋值,用来表示系统状态 
    ULONG_PTR InternalHigh;// 被系统内部赋值,传输的字节数 
    union { 
        struct { 
            DWORD Offset;//和OffsetHigh合成一个64位的整数,用来表示从文件头部的多少字节开始 
            DWORD OffsetHigh;//操作,如果不是对文件I/O来操作,则必须设定为0 
        }; 
        PVOID Pointer; 
    }; 
    HANDLE hEvent;//如果不使用,就务必设为0,否则请赋一个有效的Event句柄 
} OVERLAPPED, *LPOVERLAPPED; 

下面是异步方式使用ReadFile的一个例子 
OVERLAPPED Overlapped; 
Overlapped.Offset=345; 
Overlapped.OffsetHigh=0; 
Overlapped.hEvent=0; 
//假定其他参数都已经被初始化 
ReadFile(hFile,buffer,sizeof(buffer),&dwNumBytesRead,&Overlapped); 
这样就完成了异步方式读文件的操作,然后ReadFile函数返回,由操作系统做自己的事情,下面介绍几个与OVERLAPPED结构相关的函数 
等待重叠I/0操作完成的函数 
BOOL GetOverlappedResult (
HANDLE hFile,
LPOVERLAPPED lpOverlapped,//接受返回的重叠I/0结构
LPDWORD lpcbTransfer,//成功传输了多少字节数
BOOL fWait //TRUE只有当操作完成才返回,FALSE直接返回,如果操作没有完成,通过调//用GetLastError ( )函数会返回ERROR_IO_INCOMPLETE 
);
宏HasOverlappedIoCompleted可以帮助我们测试重叠I/0操作是否完成,该宏对OVERLAPPED结构的Internal成员进行了测试,查看是否等于STATUS_PENDING值。

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/70757.html