IO Completion Port简明教程(含例程)

2025-10-04

IO Completion Port, Windows上提供的最有效实现高性能server的方式(无论是file server, web server还是别的任何类似大量并发io请求的server),IIS本身就是基于此的。可惜,到目前为止没有一个真正简单的示例。今日便让我打响这第一炮吧。 没有一个简明例程的根源,可以说是因为IoCompletionPort本身的API设计非常糟糕,一个CreateIoCompletionPort包含了太多功能,名称又很confusing,让人云里雾里。所有的的例程,为了便于理解,都把这些让人迷惑的API封装,构造自己的class,但是呢,这样虽然从软件设计角度来说清晰了,但是对于了解IoCompletionPort的使用来说,反而更迷惑了(因为调用被分散到各个class中)。

本文的目的是用最简明的例子来介绍如何使用IO Completion Port。

在此之前,先要说IO Completion Port到底是什么东西-----就是threads pool,一个由Windows自动管理的threads pool. 好,你就需要了解这么多,再说多了就违背了本文的宗旨---提供简明例程。

1. IO Completion Port的程序,大致上可以划分为以下步骤: 2. CreateIOCompletionPort (可以理解为初始化threads pool)

3. 建立threads (就是一般的CreateThread或者_beginthreadex,将第一步所得到的HANDLE作为参数传进去,这个跟一般的thread没任何差别) 4. 开始IO 操作,比如建立SOCKET, bind...

5. 在第一个Async IO之前,将上一步建立的HANDLE(比如socket)绑定到第一步得到的IO Completion Port的HANDLE 上 6. 根据具体情况操作IO

好吧,还是用代码来看比较直接: 先来看主程序:

view plaincopy to clipboardprint?

1. int _tmain(int argc, _TCHAR* argv[]) 2. { 3.

4. // argv[1]为ip, argv[2]为port

5. // CTcpServer只是一个对socket的简单封装,代码 6. // 后面给出

7. CTcpServer server(argv[1], argv[2]); 8. if (!server.StartListening()) 9. {

10. printf(\); 11. return 1;

12. } 13.

14. // initialize IoCompletionPort

15. SOCKET& listeningSocket = server.Socket(); 16. //1. 初始化IO Completion Port

17. HANDLE hIocp = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NU

LL, NULL, 0); 18.

19. if(hIocp == NULL) 20. {

21. printf(\); 22. return 1; 23. } 24.

25. //2. 绑定socket到completion port

26. //这意思是说,后面所有在这个socket上的async 27. // io 操作,都会notify这个completion port的 28. //threads

29. if (0 == ::CreateIoCompletionPort((HANDLE)listeningSocket, hIocp

, (ULONG_PTR)0, 0)) 30. {

31. printf(\

ort\\n\);

32. return 1; 33. } 34.

35. //3. 创建threads,将io completion port 36. // HANDLE 作为参数传入,这样每个thread 37. // 都能在有IO请求时query其status,参见 38. // thread的具体代码 39. int threadPoolSize = 4; 40.

41. HANDLE hWorker; 42.

43. for(int i=0;i

45. hWorker = CreateThread(NULL, 0, WorkerThreadFunc, (LPVOID)hI

ocp, 0, NULL);

46. CloseHandle(hWorker); 47. } 48.

49. //4. 等待新连接,因为我们不要busy loop, 所以 50. // 每个TCP连接需要等待并检查

51. // FD_ACCEPT event,然后用AcceptEx

52. while(true) 53. {

54. printf(\); 55. if (server.WaitForAcceptEvent(10000)) 56. {

57. // 只管Accept了,至于Recv/Send由上面建立的 58. // thread来负责,后面会说thread的功能

59. server.AcceptNewConnection(); 60. } 61. } 62.

63. return 1; 64. }

然后先来看thread的实现. IO Completion Port的 thread因为是放入一个thread pool中,所以每个thread是“通用”的,换句话说,每个thread要能够完成多种功能,用伪代码来说是这样:

Wait For IO Notification; ---> 等待比如Socket上的一个event,至于是什么event先不管。无妨想象成interrupt,也比较类似WaitForSingleObject,总之thread在这时候是sleep的

Check IO status Operation; ----> 检查IO状态,更关键是看到底是什么Event switch (event.status) {

case ACCEPT: ... case READ: ... case WRITE: ... case WHATEVER: ... }

所以要清楚,io completion port的thread并不是去给每个read或者write建一个thread(也不是不可以,不过就是画蛇添足多此一举),而是依靠自定义的Overlapped结构来判断到底对IO进行什么操作。还是看下面的源代码吧。

view plaincopy to clipboardprint?

1. DWORD WINAPI WorkerThreadFunc(LPVOID lpParam) 2. {

3. ULONG_PTR *PerHandleKey; 4. WSAOVERLAPPED *pOverlap;

5.

6. OVERLAPPEDPLUS *pOverlapPlus, 7. *newolp; 8. DWORD dwBytesXfered; 9.

10. int ret; 11.

12. HANDLE hIocp = (HANDLE)lpParam; 13.

14. while (true) 15. {

16. //这里查询IO 状态

17. ret = GetQueuedCompletionStatus( 18. hIocp,

19. &dwBytesXfered,

20. (PULONG_PTR)&PerHandleKey, 21. &pOverlap, 22. INFINITE); 23. if (ret == 0) 24. {

25. // Operation failed

26. printf(\); 27. continue; 28. } 29.

30. //OVERLAPPEDPLUS是我们自己定义的data structure,一般把正常的 31. //OVERLAPPED作为第一个field,所以指针是指向同样地址,后面会给出具 32. //体定义. CONTAINING_RECORD是一个标准win32 macro 33.

34. pOverlapPlus = CONTAINING_RECORD(pOverlap, OVERLAPPEDPLUS, o

verlapped); 35.

36. // OP_ACCEPT也是我们自己定义的 value,只是一个标识: 37. // #define OP_ACCEPT 1 38.

39. switch (pOverlapPlus->OpCode) 40. {

41. case OP_ACCEPT:

42. printf(\);

43. //根据OVERLAPPEDPLUS的定义,一般应该有专门 44. //function来释放,不过这里就简单一下 45. free(pOverlapPlus); 46. break; 47. }

48. } 49. }

上面的OVERLAPPEDPLUS是一个很重要的自定义结构,可以把你要的东西全部放里面:D

view plaincopy to clipboardprint?

1. #pragma once 2.

3. #include 4. #include 5. #include 6. #include 7. #include 8. #include 9. #include 10. #include 11. #include 12. #include 13. #include 14. #include 15. 16.

17. #define DATA_BUFSIZE 4096 18.

19. typedef struct _OVERLAPPEDPLUS { 20. WSAOVERLAPPED overlapped; 21. SOCKET serverSock; 22. SOCKET clientSock; 23. int OpCode; 24. WSABUF wbuf; 25. DWORD Bytes; 26. DWORD Flags; 27. // other useful information 28. } OVERLAPPEDPLUS; 29.

30. #define OP_READ 0 31. #define OP_WRITE 1 32. #define OP_ACCEPT 2

好,最后就是开始提到的CTcpServer这个对socket的封装,这个类并不复杂,除开封装socket之外(无非就是socket(...),bind,listen),最重要的是检查FD_ACCEPT event,然后调用AcceptEx(如果你去看MSDN,会发现AcceptEx的示例并没有用


IO Completion Port简明教程(含例程).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:Unit10 Places of Interest_ppt

相关阅读
本类排行
× 游客快捷下载通道(下载后可以自由复制和排版)

下载本文档需要支付 7

支付方式:

开通VIP包月会员 特价:29元/月

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:xuecool-com QQ:370150219