事件通知方式实现的重叠I/O模型

//////////////////////////////////////////////////////////////////////////
/// 事件通知方式实现的重叠I/O模型(异步IO模型)
/// 这个模型的基本的设计实现是允许应用程序使用重叠的数据结构一次投递一个或者多个异步I/O
/// 请求
/// 这个模型与上述其他模型不同的是它使用Winsock2提供的异步I/O函数WSARecv。在调用WSARecv
/// 时,指定一个WSAOVERLAPPED结构,这个调用不是阻塞的,也就是说,它会立刻返回。一旦有
/// 数据到达的时候,被指定的WSAOVERLAPPED结构中的hEvent被Signaled。由于下面这个语句
/// g_CliEventArr[g_iTotalConn] = g_pPerIODataArr[g_iTotalConn]->overlap.hEvent;
/// 使得与该套接字相关联的WSAEVENT对象也被Signaled,所以WSAWaitForMultipleEvents的调用
/// 操作成功返回。我们现在应该做的就是用与调用WSARecv相同的WSAOVERLAPPED结构为参数调用
/// WSAGetOverlappedResult,从而得到本次I/O传送的字节数等相关信息。在取得接收的数据后,
/// 把数据原封不动的发送到客户端,然后重新激活一个WSARecv异步操作。
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/// 老陈:服务器应用程序,信箱:Socket,几楼几号:服务器内存
/// 后来,微软通过调查发现,老陈不喜欢上下楼收发信件,因为上下楼其实很浪费时间。
/// 于是微软再次改进他们的信箱。新式的信箱采用了更为先进的技术,只要用户告诉微软
/// 自己的家在几楼几号,新式信箱会把信件直接传送到用户的家中,然后告诉用户,你的
/// 信件已经放到你的家中了!老陈很高兴,因为他不必再亲自收发信件了! 
//////////////////////////////////////////////////////////////////////////

#include <winsock2.h>
#include <stdio.h>
#define PORT 5150
#define MSGSIZE 1024
#pragma comment(lib, "ws2_32.lib")
typedef struct
{
 WSAOVERLAPPED overlap;
//为了使用重叠I/O,每一个I/O函数都要接受一个WSAOVERLAPPED结构类型的参数

 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 = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
 
// 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(发起一个异步的I/O操作)

  
//This function receives data from a connected socket.

  WSARecv(
   g_CliSocketArr[g_iTotalConn],
//Socket的标示

   &g_pPerIODataArr[g_iTotalConn]->Buffer,
//接收数据的Buffer

   1,
   &g_pPerIODataArr[g_iTotalConn]->NumberOfBytesRecvd,
//Pointer to the number of bytes received by this call if the receive operation completes immediately

   &g_pPerIODataArr[g_iTotalConn]->Flags,
   &g_pPerIODataArr[g_iTotalConn]->overlap,
//LPWSAOVERLAPPED结构的参数

   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);
  
//注意这里应该有相应的修正的地方,WSAWaitForMultipleEvents函数在fWaitAll设置成FALSE

  
//的时候只能指定一个事件对象受信,解决方法使用for循环进行循环检测

  if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT)
  {
   continue;
  }
  index = ret - WSA_WAIT_EVENT_0;
  WSAResetEvent(g_CliEventArr[index]);
  
//获得重叠I/O的操作的结果

  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';
   
//这个是同步的I/O的操作哦

   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;
}

你可能感兴趣的:(网络编程深入研究,网络编程)