用完成例程(Completion Routine)实现的重叠I/O模型
/// 用完成例程(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模型的更多相关文章
- c++ 网络编程(十) LINUX/windows 异步通知I/O模型与重叠I/O模型 附带示例代码
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9662931.html 一.异步IO模型(asynchronous IO) (1)什么是异步I/ ...
- windows 异步通知I/O模型与重叠I/O模型
一.异步IO模型(asynchronous IO) (1)什么是异步I/O 异步I/O(asynchronous I/O)由POSIX规范定义.演变成当前POSIX规范的各种早起标准所定义的实时函数中 ...
- 重叠I/O模型
一. 重叠I/O的概念当调用ReadFile和WriteFile时,如果最后一个参数lpOverlapped设置为NULL,那么线程就阻塞在这里,直到读写完指定的数据后,它们才返回.这样在读写大文件的 ...
- windows重叠I/O模型
重叠I/O就相当于异步I/O. 一.重叠I/O的I/O完成确认 1.使用事件对象 接收端: #include <stdio.h> #include <stdlib.h> #in ...
- SAP BW 例程(Routine)【开始例程、关键值或特性的例程、结束例程】
定义 可以使用例程定义关键值或特性的复杂的转换规则. 例程是本地 ABAP 类,它们包括预定义的定义和实施范围.进站和出站参数的 TYPES及方法签名都存储在定义范围中.实际例程创建于实施范围中.使用 ...
- 四.Windows I/O模型之重叠IO(overlapped)模型
1.适用于除Windows CE之外的各种Windows平台.在使用这个模型之前应该确保该系统安装了Winsock2.重叠模型的基本设计原理是使用一个重叠的数据结构,一次投递一个或多个Winsock ...
- IOCP入门
完成端口(Completion Port)详解 此文讲解最好,也很全面一下其他文章看看就行,也可不看. 单句柄数据,单IO数据 此文讲述比较清晰,可以辅助理解上文. IOCP编程之基本原理:http: ...
- 【文件监控】之一:理解 ReadDirectoryChangesW part1
理解 ReadDirectoryChangesW 原作者:Jim Beveridge 原文:http://qualapps.blogspot.com/2010/05/understanding-rea ...
- Windows Socket知识总结
目录 0 理解Socket 1 WinSock API 2 阻塞socket 3 非阻塞Socket 4 套接字IO模型 4.1 套接字IO模型:select(选择) 4.2 套接字IO模型:W ...
随机推荐
- CodeIgniter的缓存设置
数据库缓存 数据库缓存类允许你把数据库查询结果保存在文本文件中以减少数据库访问. 激活缓存需要三步: 在服务器上创建一个可写的目录以便保存缓存文件. 在文件 application/config/da ...
- 20160129.CCPP体系详解(0008天)
程序片段(01):函数.c+call.c+测试.cpp 内容概要:函数 ///函数.c #include <stdio.h> #include <stdlib.h> //01. ...
- UVa 11384 Help is needed for Dexter 正整数序列
给定一个正整数 n ,你的任务使用最少的操作次数把序列 1, 2, 3, -- , n 中的所有数都变成 0 .每次操作可以从序列中选择一个或者多个数,同时减去一个相同的正整数.比如,1, 2, 3 ...
- 【转】Bootloader之uBoot简介(转)
原文网址:http://blog.csdn.net/sadamoo/article/details/8139946 来自http://blog.ednchina.com/hhuwxf/1915416/ ...
- Android studio gradle 打包 那些事
总结了一下 目前觉得比较好用的gradle 和一些打包 经验.放在这里. 首先说下 渠道号 这个概念,我们经常会统计我们的api 访问来源 是来自于那个app store,这有利于 我们针对性的推广. ...
- PhoneGap与Jquery Mobile结合开发android应用配置
由于工作需要,用到phonegap与jquery moblie搭配,开发android应用程序. 这些技术自己之前也都没接触过,可以说是压根没听说过,真是感慨,在开发领域,技术日新月异,知识真是永远学 ...
- Linux共享内存(一)
inux系统编程我一直看 <GNU/LINUX编程指南>,只是讲的太简单了,通常是书和网络上的资料结合着来掌握才比较全面 .在掌握了书上的内容后,再来都其他资料 . 原文链接 http:/ ...
- 【Leetcode】Reorder List JAVA
一.题目描述 Given a singly linked list L: L0→L1→…→Ln-1→Ln,reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→… You must ...
- Java之--Java语言基础组成(关键字、标识符、注释、常量和变量、运算符)
Java语言基础组成-关键字.标识符.注释.常量和变量.运算符 Java语言由8个模块构成,分别为:1.关键字:2.标识符(包名.类名.接口名.常量名.变量名等):3.注释:4.常量和变量:5.运算符 ...
- map使用.xml
map 是一种关联容器, 提供一对一的关联, 关联的形式为: KEY----VALUE 关键字不重复.multimap与map类似,但是允许关键字重复 即:关键字和与之对 ...