/// 用完成例程(Completion Routine)实现的重叠I/O模型
/// 异步IO模型
///
用完成例程来实现重叠I/O比用事件通知简单得多。在这个模型中,主线程只用不停的接受连接
///
即可;辅助线程判断有没有新的客户端连接被建立,如果有,就为那个客户端套接字激活一个
///
异步的WSARecv操作,然后调用SleepEx使线程处于一种可警告的等待状态,以使得I/O完成后
///
CompletionROUTINE可以被内核调用。如果辅助线程不调用SleepEx,则内核在完成一次I/O操作后,
///
无法调用完成例程(因为完成例程的运行应该和当初激活WSARecv异步操作的代码在同一个线程之内)。
///
完成例程内的实现代码比较简单,它取出接收到的数据,然后将数据原封不动的发送给客户端,
/// 最后重新激活另一个WSARecv异步操作。
///
注意,在这里用到了“尾随数据”。
///
我们在调用WSARecv的时候,参数lpOverlapped实际上指向一个比它大得多的结构PER_IO_OPERATION_DATA,
///
这个结构除了WSAOVERLAPPED以外,还被我们附加了缓冲区的结构信息,另外还包括客户端套接字等重要的信息。
///
这样,在完成例程中通过参数lpOverlapped拿到的不仅仅是WSAOVERLAPPED结构,
///
还有后边尾随的包含客户端套接字和接收数据缓冲区等重要信息。这样的C语言技巧在我后面介绍完成端口的时候还会使用到。
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
///
打开信封----掏出信纸----阅读信件----回复信件==>完成例程
///
老陈接收到新的信件后,一般的程序是:打开信封----掏出信纸----阅读信件----回复信件
///
......为了进一步减轻用户负担,微软又开发了一种新的技术:用户只要告诉微软对信件的
///
操作步骤,微软信箱将按照这些步骤去处理信件,不再需要用户亲自拆信/阅读/回复了!老陈
/// 终于过上了小资生活! 
//////////////////////////////////////////////////////////////////////////

#
pragma
once
#
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,
3)
;

 
// Create worker thread

CreateThread(
NULL
,
0,
WorkerThread,
NULL
,
0,
&
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,

1,

&
lpPerIOData-
>
NumberOfBytesRecvd,

&
lpPerIOData-
>
Flags,

&
lpPerIOData-
>
overlap,

CompletionROUTINE)
;

//注意这里向系统登记了一个回调函数,将会在接收数据完成的时候进行相应的调用

g_bNewConnectionArrived
=
FALSE
;

}

SleepEx(
1000,
TRUE
)
;

}

return
0;

}

void
CALLBACK CompletionROUTINE(
DWORD dwError,

DWORD cbTransferred,

LPWSAOVERLAPPED lpOverlapped,

DWORD dwFlags)

{

//注意这一句话,将LPWSAOVERLAPPED类型的lpOverlapped转化成了
LPPER_IO_OPERATION_DATA

LPPER_IO_OPERATION_DATA
lpPerIOData =
(
LPPER_IO_OPERATION_DATA)
lpOverlapped;

if
(
dwError !
=
0 |
|
cbTransferred =
=
0)

{

// Connection was closed by client

closesocket(
lpPerIOData-
>
sClient)
;

HeapFree(
GetProcessHeap(
)
,
0,
lpPerIOData)
;

}

else

{

lpPerIOData-
>
szMessage[
cbTransferred]
=
'/0'
;

send
(
lpPerIOData-
>
sClient,

lpPerIOData-
>
szMessage,
cbTransferred,
0)
;

// Launch another asynchronous
operation

memset
(
&
lpPerIOData-
>
overlap,
0,
sizeof
(
WSAOVERLAPPED)
)
;

lpPerIOData-
>
Buffer.
len
=
MSGSIZE;

lpPerIOData-
>
Buffer.
buf
=
lpPerIOData-
>
szMessage;

WSARecv(
lpPerIOData-
>
sClient,

&
lpPerIOData-
>
Buffer,

1,

&
lpPerIOData-
>
NumberOfBytesRecvd,

&
lpPerIOData-
>
Flags,

&
lpPerIOData-
>
overlap,

CompletionROUTINE)
;

}

}

用完成例程(Completion Routine)实现的重叠I/O模型的更多相关文章

  1. c++ 网络编程(十) LINUX/windows 异步通知I/O模型与重叠I/O模型 附带示例代码

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9662931.html 一.异步IO模型(asynchronous IO) (1)什么是异步I/ ...

  2. windows 异步通知I/O模型与重叠I/O模型

    一.异步IO模型(asynchronous IO) (1)什么是异步I/O 异步I/O(asynchronous I/O)由POSIX规范定义.演变成当前POSIX规范的各种早起标准所定义的实时函数中 ...

  3. 重叠I/O模型

    一. 重叠I/O的概念当调用ReadFile和WriteFile时,如果最后一个参数lpOverlapped设置为NULL,那么线程就阻塞在这里,直到读写完指定的数据后,它们才返回.这样在读写大文件的 ...

  4. windows重叠I/O模型

    重叠I/O就相当于异步I/O. 一.重叠I/O的I/O完成确认 1.使用事件对象 接收端: #include <stdio.h> #include <stdlib.h> #in ...

  5. SAP BW 例程(Routine)【开始例程、关键值或特性的例程、结束例程】

    定义 可以使用例程定义关键值或特性的复杂的转换规则. 例程是本地 ABAP 类,它们包括预定义的定义和实施范围.进站和出站参数的 TYPES及方法签名都存储在定义范围中.实际例程创建于实施范围中.使用 ...

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

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

  7. IOCP入门

    完成端口(Completion Port)详解 此文讲解最好,也很全面一下其他文章看看就行,也可不看. 单句柄数据,单IO数据 此文讲述比较清晰,可以辅助理解上文. IOCP编程之基本原理:http: ...

  8. 【文件监控】之一:理解 ReadDirectoryChangesW part1

    理解 ReadDirectoryChangesW 原作者:Jim Beveridge 原文:http://qualapps.blogspot.com/2010/05/understanding-rea ...

  9. Windows Socket知识总结

     目录 0 理解Socket 1 WinSock API 2 阻塞socket 3 非阻塞Socket 4 套接字IO模型  4.1 套接字IO模型:select(选择)  4.2 套接字IO模型:W ...

随机推荐

  1. acdream 1683 村民的怪癖(KMP,经典变形)

    Problem Description 娜娜费劲九牛二虎之力终于把糖果吃完了(说好的吃不完呢?骗人,口亨~),于是,缘溪行,忘路之远近.忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷,娜娜甚异之 ...

  2. javascript对象定义和操作

    //js对象定义有三种方式//js方法定义有三种方式 function fn(){} var fun = function(){} var fun = new function() {} //**** ...

  3. marginCollapse之兄弟关系的DIV

    废话不说,直接上图 基本代码如下: 效果图如下: 给两个div分别加marginBottom和marginTop看一下效果 实际效果如下: 我们可以看出两个div之间的距离并不是50+50,而是只显示 ...

  4. AIX 第3章 指令记录

    [ssdb01.shz.hn|oracle|/home/oracle]$oslevel -rq  --查看系统已安装的维护级别 Known Recommended Maintenance Levels ...

  5. hdu 5469 Antonidas (dfs+剪枝)2015 ACM/ICPC Asia Regional Shanghai Online

    题意: 给出一棵树,再给出每个节点上的值(一个char字符)这些值以一个字符串s1表示,然后给出一个s2字符串,问在这棵树上是否存在两个点,从一个点走到另一个点所经过的路径上的char字符组成的字符串 ...

  6. spring TaskExecutor

    TaskExecutor抽象 Spring 2.0 为执行器(Executor)处理引入了一个新的抽象层.Executor是Java 5的名词,用来表示线程池的概念.之所以用这个奇怪的名词,是因为实际 ...

  7. location.hash来保持页面状态

    /*本例是为了在客户端页面返回时保存状态,采用hash值记录的模式,为了使用方便所写的存取hash值的库,时间仓促,望指出错误.*/var pageStateHash = { hashArray: [ ...

  8. simpletest:一个简单的PHP试工具

    1. 下载: http://simpletest.org/ .2. 下载后,只要测试文件中包含如下两个文件,就可以用了 : <?php require_once('simpletest/auto ...

  9. java PO、BO

    PO(persistent object) 持久对象 在o/r映射的时候出现的概念,如果没有o/r映射,那么这个概念也就不存在了.通常对应数据模型(数据库),本身还有部分业务逻辑的处理.可以看成是与数 ...

  10. Windows上的的神技能,你知道几个?(Windows技巧大全,已更新)

    不用借助任何第三方软件,其实Windows也大有可为——比你目前了解得至少要多得多,强大技能快来get起来! 1.文件隐藏谁的电脑里没点小秘密?东藏西藏到最后自己都找不到了有木有?今天教大家个隐藏文件 ...