重叠I/O-事件通知

原文:http://network.is-programmer.com/posts/19961.html

 

重叠I/O的基本原理是让应用程序使用重叠的数据结构,投递一个或多个I/O请求。

        在winsock中的重叠数据结构定义是WSAOVERLAPPED,用来完成重叠I/O的方式有两种,1事件通知 2完成实例

        在事件通知方式中,通过WSAOVERLAPPED结构将每个socket和事件关联在一起,通过调用WSARcev等非阻塞函 数,将WSAOVERLAPPED结构体与其关联。调用WSAWaitForMultipleEvents函数等待事件,这个函数可以放到另外一个线程中 进行处理,当数据到达后会存放到之前WSARcev中的buf中。

        编程顺序如下:

        1 创建一个套接字,开始在指定的端口上侦听

        2 接收一个入站的连接请求

        3 为接受的套接字新建一个WSAOVERLAPPED结构,并为该结构分配一个事件对象句柄。也将该事件对象分配给一个事件数组,以便稍后由WSAWaitForMultipleEvents函数使用。

        4 将WSAOVERLAPPED结构指定参数,在套接字上投递一个异步WSARecv请求。

        5 使用步骤3的数组,调用WSAWaitForMultipleEvents函数,并等待与重叠调用关联在一起的事件。

        6 使用WSAGetOverlappedResult函数,判断重叠调用的返回状态

        7 函数完成后,针对事件数组,调用WSAResetEvent函数,重设事件对象,并对完成的事件请求进行处理。

        8 在套接字上重新投递另一个WSARecv请求

        9 重复步骤5-8

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <winsock2.h>
#include <stdio.h>
 
#define PORT    5500
#define MSGSIZE 1024
 
#pragma comment(lib, "ws2_32.lib")
 
typedef struct
{
     WSAOVERLAPPED overlap;
     WSABUF        Buffer;
     char           szMessage[MSGSIZE];
     DWORD          NumberOfBytesRecvd;
     DWORD          Flags;
}PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;
 
int                      g_iTotalConn = 0;
SOCKET                  g_CliSocketArr[MAXIMUM_WAIT_OBJECTS];
WSAEVENT                g_CliEventArr[MAXIMUM_WAIT_OBJECTS];
LPPER_IO_OPERATION_DATA g_pPerIODataArr[MAXIMUM_WAIT_OBJECTS];
 
DWORD WINAPI WorkerThread( LPVOID );
void Cleanup( int );
 
int main()
{
     WSADATA     wsaData;
     SOCKET      sListen, sClient;
     SOCKADDR_IN local, client;
     DWORD        dwThreadId;
     int          iaddrSize = sizeof (SOCKADDR_IN);
 
     // Initialize Windows Socket library
     WSAStartup(0x0202, &wsaData);
 
     // Create listening socket
     sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 
     // Bind
     local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
     local.sin_family = AF_INET;
     local.sin_port = htons(PORT);
     bind(sListen, ( struct sockaddr *)&local, sizeof (SOCKADDR_IN));
 
     // Listen
     listen(sListen, 3);
 
     // Create worker thread
     CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId);
 
     while (TRUE)
     {
         // Accept a connection
         sClient = accept(sListen, ( struct sockaddr *)&client, &iaddrSize);
         printf ( "Accepted client:%s:%d/n" , inet_ntoa(client.sin_addr), ntohs(client.sin_port));
 
         g_CliSocketArr[g_iTotalConn] = sClient;
 
         // Allocate a PER_IO_OPERATION_DATA structure
         g_pPerIODataArr[g_iTotalConn] = (LPPER_IO_OPERATION_DATA)HeapAlloc(
             GetProcessHeap(),
             HEAP_ZERO_MEMORY,
             sizeof (PER_IO_OPERATION_DATA));
         g_pPerIODataArr[g_iTotalConn]->Buffer.len = MSGSIZE;
         g_pPerIODataArr[g_iTotalConn]->Buffer.buf = g_pPerIODataArr[g_iTotalConn]->szMessage;
         g_CliEventArr[g_iTotalConn] = g_pPerIODataArr[g_iTotalConn]->overlap.hEvent = WSACreateEvent();
 
         // Launch an asynchronous operation
         WSARecv(
             g_CliSocketArr[g_iTotalConn],
             &g_pPerIODataArr[g_iTotalConn]->Buffer,
             1,
             &g_pPerIODataArr[g_iTotalConn]->NumberOfBytesRecvd,
             &g_pPerIODataArr[g_iTotalConn]->Flags,
             &g_pPerIODataArr[g_iTotalConn]->overlap,
             NULL);
 
         g_iTotalConn++;
     }
 
     closesocket(sListen);
     WSACleanup();
     return 0;
}
 
DWORD WINAPI WorkerThread( LPVOID lpParam)
{
     int    ret, index;
     DWORD cbTransferred;
 
     while (TRUE)
     {
         ret = WSAWaitForMultipleEvents(g_iTotalConn, g_CliEventArr, FALSE, 1000, FALSE);
         if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT)
         {
             continue ;
         }
 
         index = ret - WSA_WAIT_EVENT_0;
         WSAResetEvent(g_CliEventArr[index]);
 
         WSAGetOverlappedResult(
             g_CliSocketArr[index],
             &g_pPerIODataArr[index]->overlap,
             &cbTransferred,
             TRUE,
             &g_pPerIODataArr[g_iTotalConn]->Flags);
 
         if (cbTransferred == 0)
         {
             // The connection was closed by client
             Cleanup(index);
         }
         else
         {
             // g_pPerIODataArr[index]->szMessage contains the received data
             g_pPerIODataArr[index]->szMessage[cbTransferred] = '/0' ;
             send(g_CliSocketArr[index], g_pPerIODataArr[index]->szMessage,cbTransferred, 0);
 
             // Launch another asynchronous operation
             WSARecv(
                 g_CliSocketArr[index],
                 &g_pPerIODataArr[index]->Buffer,
                 1,
                 &g_pPerIODataArr[index]->NumberOfBytesRecvd,
                 &g_pPerIODataArr[index]->Flags,
                 &g_pPerIODataArr[index]->overlap,
                 NULL);
         }
     }
 
     return 0;
}
 
void Cleanup( int index)
{
     closesocket(g_CliSocketArr[index]);
     WSACloseEvent(g_CliEventArr[index]);
     HeapFree(GetProcessHeap(), 0, g_pPerIODataArr[index]);
 
     if (index < g_iTotalConn - 1)
     {
         g_CliSocketArr[index] = g_CliSocketArr[g_iTotalConn - 1];
         g_CliEventArr[index] = g_CliEventArr[g_iTotalConn - 1];
         g_pPerIODataArr[index] = g_pPerIODataArr[g_iTotalConn - 1];
     }
 
     g_pPerIODataArr[--g_iTotalConn] = NULL;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值