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

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

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

 

 

#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/5950451 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Overlapped I/O模型深入分析
下一篇:重叠I/O-事件通知

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月24日 06时53分21秒