重叠I/O-事件通知
发布日期:2021-06-28 22:05:21 浏览次数:3 分类:技术文章

本文共 4658 字,大约阅读时间需要 15 分钟。

原文: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;
}

转载地址:https://blog.csdn.net/yfh1985sdq/article/details/5950433 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:重叠I/O-事件通知
下一篇:C++ vector 类学习笔记

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月11日 04时35分56秒