Windows下完成端口移植Linux下的epoll

简介:
  距离上一篇博客都已经半个多月了,这么多天一直在学习研究关于Windows的完成端口移植到Linuxepoll方面的内容。这两方面以前都没有太多的接触,所以花费了较长的时间。在连续加班两天后,用一个周末的代价换来了一个调试成功。下面就把最近的成果与各位网友分享一下。如有不正确之处,望指正。
 
 先来说说Windows下的完成端口。完成端口号称是Windows下面最复杂的异步IO操作。但是如果你想开发出具有高性能的、支持大量连接的网络服务程序的话,就必须将它拿下。这里假设你已经对完成端口有一定的了解了。
 
     下面引用一下幽默讲解Windows支持的五种Socket I/O模型的例子来通俗的说一下完成端口究竟是怎么回事。
    老陈有一个在外地工作的女儿,不能经常回来,老陈和她通过信件联系。他们的信会被邮递员投递到他们的微软信箱里。
     我们平时使用的select模型,老陈每隔几分钟便到楼下看看是否有信。这样的方式会浪费老陈很多时间。同理,程序会阻塞在这里等待数据的到来,使得该进程(线程)无法进行其他的操作,导致性能的降低。
     WSAAsyncSelect模型、WSAEventSelect模型同为事件触发模型。此时,只要有信到,微软就会主动通知老陈。此时,老陈只需要等待通知即可,在等待过程中可以做其他的事情。
 Overlapped I/O 事件通知模型基本和上面两种类似。只是,老陈不需要上下楼取信了,他只需告诉微软自己在几楼几号,微软就会把信送到老陈家里。
     后来微软推出了Overlapped I/O 完成例程模型,老陈将自己拆信阅读回复的过程告诉微软,微软就会按照上述步骤去处理信件。
     但是,由于微软要处理的信件实在太多了,信箱经常崩溃。于是采用了新技术Completion Port来处理这些信件。
 
     通过Win32的重叠I/O机制,应用程序可以提请一项I/O操作,重叠的操作请求在后台完成,而同一时间提请操作的线程去做其他的事情。等重叠操作完成后线程收到有关的通知。而一个完成端口其实就是一个通知队列,由操作系统把已经完成的重叠I/O请求的通知放入其中。当某项I/O操作一旦完成,某个可以对该操作结果进行处理的工作者线程就会收到一则通知。
 
     完成端口的使用主要分两步。
     首先,创建完成端口
       
HANDLE        hIocp; 
hIocp = CreateIoCompletionPort( 
        INVALID_HANDLE_VALUE, 
        NULL, 
        (ULONG_PTR)0, 
        0); 
if (hIocp == NULL) { 
        // Error 
}
 
   完成端口创建后,要把将使用该完成端口的套接字与之关联起来。方法是再次调用CreateIoCompletionPort ()函数,第一个参数FileHandle设为套接字的句柄,第二个参数ExistingCompletionPort 设为刚刚创建的那个完成端口的句柄。
以下代码创建了一个套接字,并把它和前面创建的完成端口关联起来:
SOCKET        s; 

s = socket(AF_INET, SOCK_STREAM, 0); 

if (s == INVALID_SOCKET) { 
        // Error
}

if (CreateIoCompletionPort((HANDLE)s, 
                                       hIocp, 
                                      (ULONG_PTR)0, 
                                                        0) == NULL) 

// Error 

...
这时就完成了套接字与完成端口的关联操作。在这个套接字上进行的任何重叠操作都将通过完成端口发出完成通知。
 
    其次,使用API函数GetQueuedCompletionStatus来不断的监听查询某个完成端口的I/O操作的结果。通常来讲,在主线程中都只创建一个完成端口,将所有的套接字都与此完成端口关联。而进行监听查询的线程数一般取CPU数量的两倍。
BOOL GetQueuedCompletionStatus( 
        HANDLE CompletionPort,             // handle to completion port 
        LPDWORD lpNumberOfBytes,        // bytes transferred 
        PULONG_PTR lpCompletionKey,     // file completion key 
        LPOVERLAPPED *lpOverlapped,     // buffer 
        DWORD dwMilliseconds              // optional timeout value 
);
 
第一个参数指出了线程要监视哪一个完成端口。GetQueuedCompletionStatus使调用线程挂起,直到指定的端口的I/O完成队列中出现了一项或直到超时。同I/O完成端口相关联的第3个数据结构是使线程得到完成I/O项中的信息:传输的字节数,完成键和OVERLAPPED结构的地址。该信息是通过传递给GetQueuedCompletionSatatuslpdwNumberOfBytesTransferredlpdwCompletionKeylpOverlapped参数返回给线程的。
     注意lpOverlapped,这是很重要的一个数据结构,从这里你将获得你想要的数据,并进行判断处理。这里你可能会问,这个lpOverlapped数据结构是哪里来的,是什么类型的呢?接下来你就明白了。
 
    上面讨论了完成端口的使用,这其实是后期的处理,要想真正了解整个过程,还需要学习下面关于之前如何将发送和接收数据的I/O操作提交。
    一个是API函数WSARecv从一个套接口接收数据。
  int WSAAPI WSARecv ( SOCKET s, LPWSABUF lpBuffers, 
DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, 
LPINT lpFlags, LPWSAOVERLAPPED lpOverlapped, 
LPWSAOVERLAPPED_COMPLETION_ROUTINE 
l     pCompletionRoutine );
 
 lpOverlapped:一个指向WSAOVERLAPPED结构的指针,在这个参数中就可以设置你要接收的数据结构。
 
另一个是API函数WASSend在一个已连接的套接口上发送数据。
  int WSAAPI WSASend (    
SOCKET s,    
LPWSABUF lpBuffers, 
DWORD dwBufferCount,    
LPDWORD lpNumberOfBytesSent, 
int iFlags,    
LPWSAOVERLAPPED lpOverlapped, 
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine 
);
 
同理,lpOverlapped用来设置发送是数据结构。
 
对完成端口来说,将一个套结字邦定到完成端口后,WSARecvWSASend会立即返回,提高了系统的效率。可以调用 GetQueuedCompletionStatus来判断WSARecvWSASend是否完成。主线程接受到一个连接后,调用WSARecv等待该连接发送的数据(不阻塞,由完成端口实现数据的接受完毕判断)。在线程函数中接受完毕,然后用WSASend函数发送给客户数据(同样是不阻塞,直接返回,由完成端口判断数据是否发送完毕)。这样在线程函数中需要程序员自己设置状态来区分是发送完毕还是接受完毕。
注意WSARecv 只是向系统提交一个异步接收请求,这个请求会在有数据到达之后返回,并且放入完成队列通知工作线程,这个异步接收请求到此完成,继续提交请求是为了接收下一个数据包,也就是说,每次请求返回之后必须再次提交。WSASend也只是向系统提交一个异步发送请求,当发送成功后,需要提交WSARecv接收请求,因为发送是主动的,发送完毕后必然要等待接收对方的回复。如果不提交WSARecv接收请求,则对方发过来的数据后,完成端口不会监听。
 
先写这些,下一篇在写关于Linux下面epoll的相关内容。


本文转自jazka 51CTO博客,原文链接:http://blog.51cto.com/jazka/251759,如需转载请自行联系原作者
相关文章
|
1天前
|
人工智能 Linux iOS开发
Burp Suite Professional 2025.2 (macOS, Linux, Windows) - Web 应用安全、测试和扫描
Burp Suite Professional 2025.2 (macOS, Linux, Windows) - Web 应用安全、测试和扫描
23 12
Burp Suite Professional 2025.2 (macOS, Linux, Windows) - Web 应用安全、测试和扫描
|
4天前
|
Windows
windows查看端口占用情况
windows查看端口占用情况
27 9
|
2月前
|
Ubuntu 网络协议 Linux
快速部署WSL(Windows Subsystem for Linux)
WSL提供了一种轻量级的方法,使开发者能够在Windows上无缝运行Linux环境。通过本文介绍的步骤,可以快速安装、配置和使用WSL,以满足开发和测试的需求。
203 8
|
2月前
|
自然语言处理 安全 Java
Nexpose 7.0.1 for Linux & Windows - 漏洞扫描
Nexpose 7.0.1 for Linux & Windows - 漏洞扫描
57 6
|
2月前
|
安全 Ubuntu Linux
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
62 9
Metasploit Pro 4.22.6-2024111901 (Linux, Windows) - 专业渗透测试框架
|
2月前
|
关系型数据库 MySQL Linux
MySQL数据库下载安装教程(Windows&Linux)
本文档详细介绍了MySQL的安装步骤,包括安装前的准备工作、下载安装包、Windows和Linux系统下的具体安装流程,以及如何配置MySQL服务、设置环境变量、启动服务和连接数据库等关键操作。
|
3月前
|
NoSQL Linux PHP
如何在不同操作系统上安装 Redis 服务器,包括 Linux 和 Windows 的具体步骤
本文介绍了如何在不同操作系统上安装 Redis 服务器,包括 Linux 和 Windows 的具体步骤。接着,对比了两种常用的 PHP Redis 客户端扩展:PhpRedis 和 Predis,详细说明了它们的安装方法及优缺点。最后,提供了使用 PhpRedis 和 Predis 在 PHP 中连接 Redis 服务器及进行字符串、列表、集合和哈希等数据类型的基本操作示例。
140 4
|
3月前
|
存储 JSON Java
细谈 Linux 中的多路复用epoll
大家好,我是 V 哥。`epoll` 是 Linux 中的一种高效多路复用机制,用于处理大量文件描述符(FD)事件。相比 `select` 和 `poll`,`epoll` 具有更高的性能和可扩展性,特别适用于高并发服务器。`epoll` 通过红黑树管理和就绪队列分离事件,实现高效的事件处理。本文介绍了 `epoll` 的核心数据结构、操作接口、触发模式以及优缺点,并通过 Java NIO 的 `Selector` 类展示了如何在高并发场景中使用多路复用。希望对大家有所帮助,欢迎关注威哥爱编程,一起学习进步。
|
4月前
|
Linux 网络安全 虚拟化
适用于Linux的Windows子系统(WSL1)的安装与使用记录
并放到启动文件夹,就可以开机自动启动了。
308 0
|
4月前
|
Ubuntu 安全 Linux

热门文章

最新文章