重叠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

 

 

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值