依星源码资源网,依星资源网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

【好消息,好消息,好消息】VIP会员可以发表文章赚积分啦 !
查看: 55|回复: 0

VC++实践IOCP编程

[复制链接] 主动推送

1万

主题

1万

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
12071
发表于 2024-8-29 09:44:31 | 显示全部楼层 |阅读模式
VC++实践IOCP编程
IOCP全称I/O Completion Port,中文译为I/O完成端口。IOCP是一个异步I/O的API,它可以高效地将I/O事件通知给应用程序。与使用select()或是其它异步方法不同的是,一个套接字[socket]与一个完成端口关联了起来,然后就可继续进行正常的Winsock操作了。然而,当一个事件发生的时候,此完成端口就将被操作系统加入一个队列中。然后应用程序可以对核心层进行查询以得到此完成端口。
  这里我要对上面的一些概念略作补充,在解释[完成]两字之前,我想先简单的提一下同步和异步这两个概念,逻辑上来讲做完一件事后再去做另一件事就是同步,而同时一起做两件或两件以上事的话就是异步了。你也可以拿单线程和多线程来作比喻。但是我们一定要将同步和堵塞,异步和非堵塞区分开来,所谓的堵塞函数诸如accept(…),当调用此函数后,此时线程将挂起,直到操作系统来通知它,“HEY兄弟,有人连进来了”,那个挂起的线程将继续进行工作,也就符合”生产者-消费者”模型。堵塞和同步看上去有两分相似,但却是完全不同的概念。大家都知道I/O设备是个相对慢速的设备,不论打印机,调制解调器,甚至硬盘,与CPU相比都是奇慢无比的,坐下来等I/O的完成是一件不甚明智的事情,有时候数据的流动率非常惊人,把数据从你的文件服务器中以Ethernet速度搬走,其速度可能高达每秒一百万字节,如果你尝试从文件服务器中读取100KB,在用户的眼光来看几乎是瞬间完成,但是,要知道,你的线程执行这个命令,已经浪费了10个一百万次CPU周期。所以说,我们一般使用另一个线程来进行I/O。重叠IO[overlapped I/O]是Win32的一项技术,你可以要求操作系统为你传送数据,并且在传送完毕时通知你。这也就是[完成]的含义。这项技术使你的程序在I/O进行过程中仍然能够继续处理事务。事实上,操作系统内部正是以线程来完成overlapped I/O。你可以获得线程所有利益,而不需要付出什么痛苦的代价。
  完成端口中所谓的[端口]并不是我们在TCP/IP中所提到的端口,可以说是完全没有关系。我到现在也没想通一个I/O设备[I/O Device]和端口[IOCP中的Port]有什么关系。估计这个端口也迷惑了不少人。IOCP只不过是用来进行读写操作,和文件I/O倒是有些类似。既然是一个读写设备,我们所能要求它的只是在处理读与写上的高效。
  1. #include <stdio.h>
  2. #include <windows.h>

  3. // 初始化Winsock库
  4. CInitSock theSock;

  5. #define BUFFER_SIZE 1024

  6. typedef struct _PER_HANDLE_DATA                // per-handle数据
  7. {
  8.         SOCKET s;                        // 对应的套节字句柄
  9.         sockaddr_in addr;        // 客户方地址
  10. } PER_HANDLE_DATA, *PPER_HANDLE_DATA;


  11. typedef struct _PER_IO_DATA                        // per-I/O数据
  12. {
  13.         OVERLAPPED ol;                        // 重叠结构
  14.         char buf[BUFFER_SIZE];        // 数据缓冲区
  15.         int nOperationType;                // 操作类型
  16. #define OP_READ   1
  17. #define OP_WRITE  2
  18. #define OP_ACCEPT 3
  19. } PER_IO_DATA, *PPER_IO_DATA;


  20. DWORD WINAPI ServerThread(LPVOID lpParam)
  21. {
  22.         // 得到完成端口对象句柄
  23.         HANDLE hCompletion = (HANDLE)lpParam;

  24.         DWORD dwTrans;
  25.         PPER_HANDLE_DATA pPerHandle;
  26.         PPER_IO_DATA pPerIO;
  27.         while(TRUE)
  28.         {
  29.                 // 在关联到此完成端口的所有套节字上等待I/O完成
  30.                 BOOL bOK = ::GetQueuedCompletionStatus(hCompletion,
  31.                         &dwTrans, (LPDWORD)&pPerHandle, (LPOVERLAPPED*)&pPerIO, WSA_INFINITE);
  32.                 if(!bOK)                                                // 在此套节字上有错误发生
  33.                 {
  34.                         ::closesocket(pPerHandle->s);
  35.                         ::GlobalFree(pPerHandle);
  36.                         ::GlobalFree(pPerIO);
  37.                         continue;
  38.                 }
  39.                
  40.                 if(dwTrans == 0 &&                                // 套节字被对方关闭
  41.                         (pPerIO->nOperationType == OP_READ || pPerIO->nOperationType == OP_WRITE))       
  42.                        
  43.                 {
  44.                         ::closesocket(pPerHandle->s);
  45.                         ::GlobalFree(pPerHandle);
  46.                         ::GlobalFree(pPerIO);
  47.                         continue;
  48.                 }

  49.                 switch(pPerIO->nOperationType)        // 通过per-I/O数据中的nOperationType域查看什么I/O请求完成了
  50.                 {
  51.                 case OP_READ:        // 完成一个接收请求
  52.                         {
  53.                                 pPerIO->buf[dwTrans] = '\0';
  54.                                 printf(pPerIO -> buf);
  55.                                
  56.                                 // 继续投递接收I/O请求
  57.                                 WSABUF buf;
  58.                                 buf.buf = pPerIO->buf ;
  59.                                 buf.len = BUFFER_SIZE;
  60.                                 pPerIO->nOperationType = OP_READ;

  61.                                 DWORD nFlags = 0;
  62.                                 ::WSARecv(pPerHandle->s, &buf, 1, &dwTrans, &nFlags, &pPerIO->ol, NULL);
  63.                         }
  64.                         break;
  65.                 case OP_WRITE: // 本例中没有投递这些类型的I/O请求
  66.                 case OP_ACCEPT:
  67.                         break;
  68.                 }
  69.         }
  70.         return 0;
  71. }


  72. void main()
  73. {
  74.         int nPort = 4567;
  75.         // 创建完成端口对象,创建工作线程处理完成端口对象中事件
  76.         HANDLE hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
  77.         ::CreateThread(NULL, 0, ServerThread, (LPVOID)hCompletion, 0, 0);

  78.         // 创建监听套节字,绑定到本地地址,开始监听
  79.         SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, 0);
  80.         SOCKADDR_IN si;
  81.         si.sin_family = AF_INET;
  82.         si.sin_port = ::ntohs(nPort);
  83.         si.sin_addr.S_un.S_addr = INADDR_ANY;
  84.         ::bind(sListen, (sockaddr*)&si, sizeof(si));
  85.         ::listen(sListen, 5);

  86.         // 循环处理到来的连接
  87.         while(TRUE)
  88.         {
  89.                 // 等待接受未决的连接请求
  90.                 SOCKADDR_IN saRemote;
  91.                 int nRemoteLen = sizeof(saRemote);
  92.                 SOCKET sNew = ::accept(sListen, (sockaddr*)&saRemote, &nRemoteLen);

  93.                 // 接受到新连接之后,为它创建一个per-handle数据,并将它们关联到完成端口对象。
  94.                 PPER_HANDLE_DATA pPerHandle =
  95.                                                         (PPER_HANDLE_DATA)::GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
  96.                 pPerHandle->s = sNew;
  97.                 memcpy(&pPerHandle->addr, &saRemote, nRemoteLen);
  98.                 ::CreateIoCompletionPort((HANDLE)pPerHandle->s, hCompletion, (DWORD)pPerHandle, 0);
  99.        
  100.                 // 投递一个接收请求
  101.                 PPER_IO_DATA pPerIO = (PPER_IO_DATA)::GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
  102.                 pPerIO->nOperationType = OP_READ;
  103.                 WSABUF buf;
  104.                 buf.buf = pPerIO->buf;
  105.                 buf.len = BUFFER_SIZE;       
  106.                 DWORD dwRecv;
  107.                 DWORD dwFlags = 0;
  108.                 ::WSARecv(pPerHandle->s, &buf, 1, &dwRecv, &dwFlags, &pPerIO->ol, NULL);
  109.         }
  110. }
复制代码


相关帖子

扫码关注微信公众号,及时获取最新资源信息!下载附件优惠VIP会员5折;永久VIP免费
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

免责声明:
1、本站提供的所有资源仅供参考学习使用,版权归原著所有,禁止下载本站资源参与商业和非法行为,请在24小时之内自行删除!
2、本站所有内容均由互联网收集整理、网友上传,并且以计算机技术研究交流为目的,仅供大家参考、学习,请勿任何商业目的与商业用途。
3、若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。
4、论坛的所有内容都不保证其准确性,完整性,有效性,由于源码具有复制性,一经售出,概不退换。阅读本站内容因误导等因素而造成的损失本站不承担连带责任。
5、用户使用本网站必须遵守适用的法律法规,对于用户违法使用本站非法运营而引起的一切责任,由用户自行承担
6、本站所有资源来自互联网转载,版权归原著所有,用户访问和使用本站的条件是必须接受本站“免责声明”,如果不遵守,请勿访问或使用本网站
7、本站使用者因为违反本声明的规定而触犯中华人民共和国法律的,一切后果自己负责,本站不承担任何责任。
8、凡以任何方式登陆本网站或直接、间接使用本网站资料者,视为自愿接受本网站声明的约束。
9、本站以《2013 中华人民共和国计算机软件保护条例》第二章 “软件著作权” 第十七条为原则:为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。若有学员需要商用本站资源,请务必联系版权方购买正版授权!
10、本网站如无意中侵犯了某个企业或个人的知识产权,请来信【站长信箱312337667@qq.com】告之,本站将立即删除。
郑重声明:
本站所有资源仅供用户本地电脑学习源代码的内含设计思想和原理,禁止任何其他用途!
本站所有资源、教程来自互联网转载,仅供学习交流,不得商业运营资源,不确保资源完整性,图片和资源仅供参考,不提供任何技术服务。
本站资源仅供本地编辑研究学习参考,禁止未经资源商正版授权参与任何商业行为,违法行为!如需商业请购买各资源商正版授权
本站仅收集资源,提供用户自学研究使用,本站不存在私自接受协助用户架设游戏或资源,非法运营资源行为。
 
在线客服
点击这里给我发消息 点击这里给我发消息 点击这里给我发消息
售前咨询热线
312337667

微信扫一扫,私享最新原创实用干货

QQ|免责声明|小黑屋|依星资源网 ( 鲁ICP备2021043233号-3 )|网站地图

GMT+8, 2024-11-24 03:14

Powered by Net188.com X3.4

邮箱:312337667@qq.com 客服QQ:312337667(工作时间:9:00~21:00)

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