#include <WINSOCK2.H>
#include <stdio.h> #define PORT 5150
#define MSGSIZE 1024 #pragma comment(lib, "ws2_32.lib") typedef struct
{
WSAOVERLAPPED overlap;
WSABUF Buffer;
char szMessage[MSGSIZE];
DWORD NumberOfBytesRecvd;
DWORD Flags;
SOCKET sClient;
}PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA; DWORD WINAPI WorkerThread(LPVOID);
void CALLBACK CompletionROUTINE(DWORD, DWORD, LPWSAOVERLAPPED, DWORD); SOCKET g_sNewClientConnection;
BOOL g_bNewConnectionArrived = FALSE; int main()
{
WSADATA wsaData;
SOCKET sListen;
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, ); // Create worker thread
CreateThread(NULL, , WorkerThread, NULL, , &dwThreadId); while (TRUE)
{
// Accept a connection
g_sNewClientConnection = accept(sListen, (struct sockaddr *)&client, &iaddrSize);
g_bNewConnectionArrived = TRUE;
printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
}
} DWORD WINAPI WorkerThread(LPVOID lpParam)
{
LPPER_IO_OPERATION_DATA lpPerIOData = NULL; while (TRUE)
{
if (g_bNewConnectionArrived)
{
// Launch an asynchronous operation for new arrived connection
lpPerIOData = (LPPER_IO_OPERATION_DATA)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(PER_IO_OPERATION_DATA));
lpPerIOData->Buffer.len = MSGSIZE;
lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
lpPerIOData->sClient = g_sNewClientConnection; WSARecv(lpPerIOData->sClient,
&lpPerIOData->Buffer,
,
&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flags,
&lpPerIOData->overlap,
CompletionROUTINE); g_bNewConnectionArrived = FALSE;
} SleepEx(, TRUE);                  //这里如果不sleep,根本不会进入完成例程的回调,第一个参数时间可以适当缩小
}
return ;
} void CALLBACK CompletionROUTINE(DWORD dwError,
DWORD cbTransferred,
LPWSAOVERLAPPED lpOverlapped,
DWORD dwFlags)
{
LPPER_IO_OPERATION_DATA lpPerIOData = (LPPER_IO_OPERATION_DATA)lpOverlapped;   if (dwError != || cbTransferred == )
  {
  // Connection was closed by client
  closesocket(lpPerIOData->sClient);
  HeapFree(GetProcessHeap(), , lpPerIOData);
  }
  else
{
lpPerIOData->szMessage[cbTransferred] = '\0';
send(lpPerIOData->sClient, lpPerIOData->szMessage, cbTransferred, ); // Launch another asynchronous operation
memset(&lpPerIOData->overlap, , sizeof(WSAOVERLAPPED));
lpPerIOData->Buffer.len = MSGSIZE;
lpPerIOData->Buffer.buf = lpPerIOData->szMessage; WSARecv(lpPerIOData->sClient,
&lpPerIOData->Buffer,
,
&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flags,
&lpPerIOData->overlap,
CompletionROUTINE);
}
}

这个模型中有两个函数可以交换着用,那就是WSAWaitForMultipleEvents()和SleepEx()函数,前者需要一个事件驱动,后者则不需要。是不是听起来后者比较厉害,当然不是,简单肯定是拿某种性能换来的,那就是当多client同时发出请求的时候,SleepEx如果等候时间设置成比较大的话,会造成client连接不上的现象。具体可以运行一下示例代码体会一下。

用完成例程来实现重叠I/O比用事件通知简单得多。在这个模型中,主线程只用不停的接受连接即可;辅助线程判断有没有新的客户端连接被建立,如果有,就为那个客户端套接字激活一个异步的WSARecv操作,然后调用SleepEx使线程处于一种可警告的等待状态,以使得I/O完成后CompletionROUTINE可以被内核调用。如果辅助线程不调用SleepEx,则内核在完成一次I/O操作后,无法调用完成例程(因为完成例程的运行应该和当初激活WSARecv异步操作的代码在同一个线程之内)。

完成例程内的实现代码比较简单,它取出接收到的数据,然后将数据原封不动的发送给客户端,最后重新激活另一个WSARecv异步操作。注意,在这里用到了“尾随数据”。我们在调用WSARecv的时候,参数lpOverlapped实际上指向一个比它大得多的结构PER_IO_OPERATION_DATA,这个结构除了WSAOVERLAPPED以外,还被我们附加了缓冲区的结构信息,另外还包括客户端套接字等重要的信息。这样,在完成例程中通过参数lpOverlapped拿到的不仅仅是WSAOVERLAPPED结构,还有后边尾随的包含客户端套接字和接收数据缓冲区等重要信息。这样的C语言技巧在我后面介绍完成端口的时候还会使用到。

windows网络模型之重叠IO(完成例程)的使用的更多相关文章

  1. windows网络模型之重叠IO的使用

    大部分内容转载自https://blog.csdn.net/piggyxp/article/details/114883 目录: 1. 重叠模型的优点 2. 重叠模型的基本原理 3. 关于重叠模型的基 ...

  2. 四.Windows I/O模型之重叠IO(overlapped)模型

    1.适用于除Windows CE之外的各种Windows平台.在使用这个模型之前应该确保该系统安装了Winsock2.重叠模型的基本设计原理是使用一个重叠的数据结构,一次投递一个或多个Winsock ...

  3. winSocket编程(九)重叠IO

    重叠模型的优点 重叠模型的基本原理 关于重叠模型的基础知识 重叠模型的实现步骤 多客户端情况的注意事项 一.重叠模型的优点 1.可以运行在支持Winsock2的所有Windows平台 ,而不像完成端口 ...

  4. 重叠IO

    一. 异步IO        说到重叠模型首先还是提一下异步IO比较好,因为从本质上讲,重叠模型也是一种异步IO模型.       我们知道,相对于计算机执行的其他操作而言,设备IO(文件.管道.套接 ...

  5. 重叠io操作

    第一章 一. 重叠模型的优点 1. 可以运行在支持Winsock2的所有Windows平台 ,而不像完成端口只是支持NT系统. 2. 比起阻塞.select.WSAAsyncSelect以及WSAEv ...

  6. windows网络模型

    Windows提供了四种异步IO技术,机制几乎时相同的,区别在于通知结果的方式不同: 1.通过注册的消息函数进行通知 2.通过内核event事件进行通知 3.通过称为完成例程的回调函数进行通知 4.通 ...

  7. Windows内核原理-同步IO与异步IO

    目录 Windows内核原理-同步IO与异步IO 背景 目的 I/O 同步I/O 异步I/O I/O完成通知 总结 参考文档 Windows内核原理-同步IO与异步IO 背景 在前段时间检查异常连接导 ...

  8. 重叠IO 模型

    1. 重叠模型的优点 2. 重叠模型的基本原理 3. 关于重叠模型的基础知识 4. 重叠模型的实现步骤 5. 多客户端情况的注意事项 一.重叠模型的优点   1.可以运行在支持Winsock2的所有W ...

  9. Socket重叠IO

    1.为什么到现在才弄懂这个 不知道这个Socket重叠IO这种模型是不是socket IO完成端口的基础,不过我感觉,学习一下这个再去学习socket IO完成端口是比较有好处的. 这个Scoket重 ...

随机推荐

  1. 使用类和对象、方法、循环、List、泛型来实现简单的图书管理系统

    Book.java import java.util.List; import java.util.Scanner; public class Book { private String name; ...

  2. spark SQL编程

    1.编程实现将 RDD 转换为 DataFrame源文件内容如下(包含 id,name,age): 1,Ella,362,Bob,293,Jack,29 请将数据复制保存到 Linux 系统中,命名为 ...

  3. VUE项目引入微信jssdk

    npm i -S weixin-js-sdkimport wx from 'weixin-js-sdk'

  4. Map接口常用实现类学习

    HashMap 1.6的HashMap:数组加单向链表结构 最重要的内部类Entry,全类名是java.util.HashMap.Entry,是个静态类,实现了Map.Entry接口.HashMap. ...

  5. curl -w函数

    url_effective 最终获取的url地址,尤其是当你指定给curl的地址存在301跳转,且通过-L继续追踪的情形. http_code http状态码,如200成功,301转向,404未找到, ...

  6. XLua 网络加载(基础操作)

    LoadGameMethod  网上资源加载更新:加载场景中另建协程用来加载; public void LoadGameMethod() { StartCoroutine(start());      ...

  7. TOJ 4002 Palindrome Generator

    描述 A palindrome is a number that reads the same whether you read it from left to right or from right ...

  8. BNU 20860——Forwarding Emails——————【强连通图缩点+记忆化搜索】

    Forwarding Emails Time Limit: 1000ms Memory Limit: 131072KB This problem will be judged on UVA. Orig ...

  9. MYSQL冷知识——ON DUPLICATE KEY 批量增删改

    一 有个需求要批量增删改,并且是混合的,也就是仅不存在才增. 删简单,因为有个deleteStaute之类的字段,删除本质上就是就是一个修改 所以就是实现批量混合增改,然而组长说mysql不支持混合增 ...

  10. 服务器LIUNX之如何解决矿机问题

    点进来的基本都是遇到liunx变矿机的小伙伴吧(cpu运载300%) 卡的连终端都很难打开 开下来之后提示 大意是, 到xxx网站给钱了事, 不过基本这个网站基本也上不去, 要么是暴力破解, 要么是通 ...