//
/// 事件通知方式实现的重叠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;
}

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

  1. 基于 WEB 的实时事件通知方式 服务器推送

    下面这些可以实现基于web的实时事件通知的方法.在他们的实验性研究中在一个利用COMET推送方式实现(Dojo的Cometd库,dwr的反向Ajax)的AJAX应用和一个纯拉取方式的应用之间,对数据一 ...

  2. 基于WEB 的实时事件通知方案

    基于WEB 的实时事件通知方案 基于 WEB 的实时事件通知方式大致有五种方案:HTTP拉取方式(pull),HTTP流,Long Polling,FlashXMLSocket方式,Java Appl ...

  3. 基于WEB 的实时事件通知

    基于 WEB 的实时事件通知方式大致有五种方案:HTTP拉取方式(pull),HTTP流,Long Polling,Flash XMLSocket方式,java Applet. 首先说下Comet这个 ...

  4. 用完成例程(Completion Routine)实现的重叠I/O模型

    // /// 用完成例程(Completion Routine)实现的重叠I/O模型 /// 异步IO模型 /// 用完成例程来实现重叠I/O比用事件通知简单得多.在这个模型中,主线程只用不停的接受连 ...

  5. 学习笔记(07):C++网络编程进阶-IO模型之重叠Overlapped IO(基于事件通知)

    立即学习:https://edu.csdn.net/course/play/6082/113760?utm_source=blogtoedu 重叠Overlapped IO模型 重叠模型让应用程序使用 ...

  6. IO模型之重叠Overlapped IO基于事件通知

    文章目录 1. 重叠Overlapped IO模型 2. 重叠Overlapped IO模型的优点 3. 重叠IO请求的通知的方式 4. 重叠I0基于事件通知的流程 5. WSAOVERLAPPED结 ...

  7. socket通信之六:Overlapped I/O 事件通知模型实现的客户/服务器模型

    1.基于事件通知模型的Overlapped I/O(重叠IO模型) 概括一点说,重叠模型是让应用程序使用重叠数据结构(WSAOVERLAPPED),一次投递一个或多个Winsock I/O请求.针对这 ...

  8. WMI技术介绍和应用——事件通知

    在<WMI技术介绍和应用--WMI概述>中,我们使用了下图介绍WMI构架(转载请指明出于breaksoftware的csdn博客) 我们之前介绍的使用WMI查询系统.硬件等信息的功能,是通 ...

  9. spring事件通知机制详解

    优势 解耦 对同一种事件有多种处理方式 不干扰主线(main line) 起源 要讲spring的事件通知机制,就要先了解一下spring中的这些接口和抽象类: ApplicationEventPub ...

最新文章

  1. 35个立体动感的视差滚动效果网站作品
  2. HBase 系统架构
  3. Oracle闪回详解
  4. 玩转GIT系列之【git pull和git fetch的区别】
  5. C++和Opencv4.5 实现全景图像拼接
  6. 算法题解:旋转数组的最小数字
  7. Win10 取消桌面快捷键图标
  8. 《天谕》全新PBR技术曝光 布料纹路清晰可见
  9. 【重磅分享】从零到一搭建推荐系统指南白皮书.pdf(附48页下载链接)
  10. P5 周志华:“数据、算法、算力”,人工智能三要素在未来还要加上“知识”
  11. 蓝桥杯题目练习 水题 [蓝桥杯2019初赛]质数
  12. 代码对比工具 mac
  13. C语言中的运算符大全(内附优先级表)
  14. Xshell上传文件
  15. 扫雷小游戏制作全过程
  16. java手势识别技术_Android基础开发之手势识别
  17. 楼天城楼教主的acm心路历程 ---- 抄自网上
  18. M - Maratona Brasileira de Popcorn(SDUT 2019 Autumn Team Contest 6th)
  19. Linux 入门基本操作
  20. 天是岸:优秀的网络营销推广人,身上一般都具备这7大特质

热门文章

  1. 新增房源服务实现之AutoGenerator使用以及创建pojo对象
  2. Shiro结合redis的统一会话管理:自定义会话管理器
  3. 封装案例-完成开火方法
  4. 列表-列表的排序和反转
  5. SpringBoot_web开发-SpringMVC自动配置原理
  6. redis(16)--sentinel
  7. html5的api有什么区别,HTML入门--浅谈HTML和HTML5有什么区别?
  8. php短信接口加密_PHP短信接口、PHP短信验证码接口源码
  9. Java 函数式编程入门
  10. 2019年我总结的前端面试题