设为首页 收藏本站
查看: 540|回复: 0

[经验分享] Windows下完成端口移植Linux下的epoll

[复制链接]

尚未签到

发表于 2018-6-12 09:46:00 | 显示全部楼层 |阅读模式

     距离上一篇博客都已经半个多月了,这么多天一直在学习研究关于Windows的完成端口移植到Linux下epoll方面的内容。这两方面以前都没有太多的接触,所以花费了较长的时间。在连续加班两天后,用一个周末的代价换来了一个调试成功。下面就把最近的成果与各位网友分享一下。如有不正确之处,望指正。

先来说说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结构的地址。该信息是通过传递给GetQueuedCompletionSatatus的lpdwNumberOfBytesTransferred,lpdwCompletionKey和lpOverlapped参数返回给线程的。
     注意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用来设置发送是数据结构。

对完成端口来说,将一个套结字邦定到完成端口后,WSARecv和WSASend会立即返回,提高了系统的效率。可以调用 GetQueuedCompletionStatus来判断WSARecv和WSASend是否完成。主线程接受到一个连接后,调用WSARecv等待该连接发送的数据(不阻塞,由完成端口实现数据的接受完毕判断)。在线程函数中接受完毕,然后用WSASend函数发送给客户数据(同样是不阻塞,直接返回,由完成端口判断数据是否发送完毕)。这样在线程函数中需要程序员自己设置状态来区分是发送完毕还是接受完毕。
注意WSARecv 只是向系统提交一个异步接收请求,这个请求会在有数据到达之后返回,并且放入完成队列通知工作线程,这个异步接收请求到此完成,继续提交请求是为了接收下一个数据包,也就是说,每次请求返回之后必须再次提交。WSASend也只是向系统提交一个异步发送请求,当发送成功后,需要提交WSARecv接收请求,因为发送是主动的,发送完毕后必然要等待接收对方的回复。如果不提交WSARecv接收请求,则对方发过来的数据后,完成端口不会监听。

先写这些,下一篇在写关于Linux下面epoll的相关内容。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-522586-1-1.html 上篇帖子: Windows产品密钥 下篇帖子: Windows 2003 Server 系统中证书服务
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表