Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1501214
  • 博文数量: 218
  • 博客积分: 6394
  • 博客等级: 准将
  • 技术积分: 2563
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-08 15:33
个人简介

持之以恒

文章分类

全部博文(218)

文章存档

2013年(8)

2012年(2)

2011年(21)

2010年(55)

2009年(116)

2008年(16)

分类: 网络与安全

2010-01-03 15:21:16

//////////////////////////////////////////////////////////////////////////
/// WSAAsyncEvent模型(同步I/O模型)
///这里为什么说他是同步的,就是因为实际的数据的Copy是同步进行///的,而不是异步的,只是相应的通知机制(通知数据已经准备好了),///是异步的
/// 和WSAAsyncSelect模型类似的是,它也允许应用程序在一个或多个套接字上,接收以事件为
/// 基础的网络事件通知。在用新模型开发的应用程序中,也能接收和处理所有那些事件。
/// 该模型最主要的差别在于网络事件会投递至一个事件对象句柄,而非投递至一个窗口例程。
/// 它的基本思想是将每个套接字都和一个WSAEVENT对象对应起来,并且在关联的时候指定需要
/// 关注的哪些网络事件。一旦在某个套接字上发生了我们关注的事件(FD_READ和FD_CLOSE),
/// 与之相关联的WSAEVENT对象被Signaled。
/// 程序定义了两个全局数组,一个套接字数组,一个WSAEVENT对象数组,其大小都是MAXIMUM_WAIT_OBJECTS(64),
/// 两个数组中的元素一一对应。
//////////////////////////////////////////////////////////////////////////
/// WSAEventSelect function specifies an event object to be associated with the supplied set of
/// FD_XXX network events.
//////////////////////////////////////////////////////////////////////////
/// 附加装置:事件监视器的集合,每一个事件监视器监视一个Socket上的相应的相应的行为
/// 微软的信箱非常畅销,购买微软信箱的人以百万计数......以至于盖茨每天24小时给客户打电话
/// ,累得腰酸背痛,喝蚁力神都不好使。微软改进了他们的信箱:在客户的家中添加一个附加装置
/// ,这个装置会监视客户的信箱,每当新的信件来临,此装置会发出“新信件到达”声,提醒老陈
/// 去收信。盖茨终于可以睡觉了。 
//////////////////////////////////////////////////////////////////////////

#include <winsock2.h>
#include <stdio.h>
#define PORT 5150
#define MSGSIZE 1024
#pragma comment(lib, "ws2_32.lib")
int g_iTotalConn = 0;
SOCKET g_CliSocketArr[MAXIMUM_WAIT_OBJECTS];
WSAEVENT g_CliEventArr[MAXIMUM_WAIT_OBJECTS];
DWORD WINAPI WorkerThread(LPVOID);
void Cleanup(int index);
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));
  
// Associate socket with network event

  g_CliSocketArr[g_iTotalConn] = sClient;
  g_CliEventArr[g_iTotalConn] = WSACreateEvent();
  WSAEventSelect(g_CliSocketArr[g_iTotalConn],
   g_CliEventArr[g_iTotalConn],
   FD_READ | FD_CLOSE);
  g_iTotalConn++;
 }
}
DWORD WINAPI WorkerThread(LPVOID lpParam)
{
 int ret, index;
 WSANETWORKEVENTS NetworkEvents;
 char szMessage[MSGSIZE];
 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;
  
//查看发生了什么网络事件

  WSAEnumNetworkEvents(g_CliSocketArr[index], g_CliEventArr[index], &NetworkEvents);
  if (NetworkEvents.lNetworkEvents & FD_READ)
  {
   
// Receive message from client

   ret = recv(g_CliSocketArr[index], szMessage, MSGSIZE, 0);
   if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
   {
    Cleanup(index);
   }
   else
   {
    szMessage[ret] = '\0';
    send(g_CliSocketArr[index], szMessage, strlen(szMessage), 0);
   }
  }
  if (NetworkEvents.lNetworkEvents & FD_CLOSE)
  {
   Cleanup(index);
  }
 }
 return 0;
}
void Cleanup(int index)
{
 closesocket(g_CliSocketArr[index]);
 WSACloseEvent(g_CliEventArr[index]);
 if (index < g_iTotalConn - 1)
 {
  g_CliSocketArr[index] = g_CliSocketArr[g_iTotalConn - 1];
  g_CliEventArr[index] = g_CliEventArr[g_iTotalConn - 1];
 }
 g_iTotalConn--;
}


阅读(1456) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~