手把手教你玩转网络编程模型之完成例程(Completion Routine)篇

合集下载

C++中的异步网络编程和高并发服务器

C++中的异步网络编程和高并发服务器

C++中的异步网络编程和高并发服务器异步网络编程是一种处理网络通信的方式,它使得程序可以在发送或接收数据的同时执行其他任务,而不会阻塞整个程序的流程。

在C++中,异步网络编程可以通过使用相关的库来实现,比如Boost.Asio、libevent等。

高并发服务器则是指能够同时处理大量客户端请求的服务器,通过并发处理技术来提高服务器的性能和吞吐量。

在实现高并发服务器时,通常会涉及到线程管理、事件驱动等方面的技术。

在C++中,异步网络编程和高并发服务器经常结合使用,以提高服务器的性能和效率。

下面将分别讨论异步网络编程和高并发服务器在C++中的实现方式。

一、异步网络编程1.异步编程模型在异步网络编程中,程序通过注册回调函数或者使用Future/Promise等机制来实现异步操作。

通过这种方式,程序可以在发送或接收数据时继续执行其他任务,而不会阻塞在网络操作上。

2. Boost.Asio库Boost.Asio是一个高性能的异步I/O库,它提供了异步网络编程所需的各种功能,比如异步socket、定时器、协程等。

通过使用Boost.Asio,可以方便地实现异步网络通信,提高程序的性能和可维护性。

3.异步通信模式在异步网络编程中,常见的通信模式有事件驱动模型和回调模型。

事件驱动模型通过事件循环来处理网络事件,而回调模型则通过注册回调函数来处理异步操作的结果。

二、高并发服务器1.线程管理在高并发服务器中,通常会通过多线程来同时处理多个客户端请求。

通过合理管理线程池和线程间通信,可以提高服务器的并发处理能力。

2.事件驱动事件驱动是另一种提高服务器性能的方式,通过事件循环和事件处理函数来处理客户端请求。

在C++中,可以使用库如libevent、libuv等来实现事件驱动的服务器。

3.内存管理和资源池在高并发服务器中,合理管理内存和资源是至关重要的。

通过使用内存池、连接池等技术,可以减少资源的分配和释放开销,提高服务器的性能和稳定性。

并发编程的七个模型

并发编程的七个模型

并发编程的七个模型线程与锁:线程与锁模型有很多众所周知的不⾜,但仍是其他模型的技术基础,也是很多并发软件开发的⾸选。

函数式编程:函数式编程⽇渐重要的原因之⼀,是其对并发编程和并⾏编程提供了良好的⽀持。

函数式编程消除了可变状态,所以从根本上是线程安全的,⽽且易于并⾏执⾏。

Clojure之道——分离标识与状态:编程语⾔Clojure是⼀种指令式编程和函数式编程的混搭⽅案,在两种编程⽅式上取得了微妙的平衡来发挥两者的优势。

actor:actor模型是⼀种适⽤性很⼴的并发编程模型,适⽤于共享内存模型和分布式内存模型,也适合解决地理分布型问题,能提供强⼤的容错性。

通信顺序进程(Communicating Sequential Processes,CSP):表⾯上看,CSP模型与actor模型很相似,两者都基于消息传递。

不过CSP模型侧重于传递信息的通道,⽽actor模型侧重于通道两端的实体,使⽤CSP模型的代码会带有明显不同的风格。

数据级并⾏:每个笔记本电脑⾥都藏着⼀台超级计算机——GPU。

GPU利⽤了数据级并⾏,不仅可以快速进⾏图像处理,也可以⽤于更⼴阔的领域。

如果要进⾏有限元分析、流体⼒学计算或其他的⼤量数字计算,GPU的性能将是不⼆选择。

Lambda架构:⼤数据时代的到来离不开并⾏——现在我们只需要增加计算资源,就能具有处理TB级数据的能⼒。

Lambda架构综合了MapReduce和流式处理的特点,是⼀种可以处理多种⼤数据问题的架构。

1. 线程与锁原始,底层(既是优点也是缺点),有效,仍然是开发并发软件的⾸选。

⼏乎每种编程语⾔都以某种形式提供了⽀持,我们应该了解底层的原理,但是,多数时候,应该使⽤更上层的类库,更⾼效,更不易出错。

这种⽅式⽆外乎⼏种经典的模式,互斥锁(临界区),⽣产者-消费者,同步等等。

书中举了个外星⽅法的⽰例,即使我们⾃⼰的代码没有死锁,但是你不知道调⽤的⽅法做了什么,或许就会导致死锁。

网络程序设计_socket_复习题_考点_知识点

网络程序设计_socket_复习题_考点_知识点

Winsock是什么?• Windows下网络编程的规范• Windows下得到广泛应用的、开放的、支持多种协议的网络编程接口。

• 已成为Windows网络编程的事实上的标准。

Windows socket规范• Windows Socket规范本意在于提供给应用程序开发者一套简单的API,并让各家网络软件供应商共同遵守。

Socket原理• Socket通常称为套接字、套管、插口,是两个程序间通信链路的端点。

• Socket实际上是一个编程接口,为网络应用程序提供各种接口函数。

Winsock基本概念• 多数网络协议都由软件实现,而且几乎所有计算机系统都将网络协议的实现作为操作系统的一部分,操作系统提供给用户的程序接口叫做应用程序编程接口(API )。

• 套接字接口(Socket Interface)就是一种API套接字及类型• 套接字(socket)是网络通信的基本构件,是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和与之相连的进程。

• 套接字存在于通信区域中,通信区域也称地址族• 套接字通常只与同一区域中的套接字交换数据(也可跨区域通信,但要执行某种转换进程之后才能实现)。

• TCP/IP的socket提供三种类型的套接字:流式套接字(SOCK_STREAM)• 提供一个面向连接的、可靠的数据传输服务,• 内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制。

• 文件传输协议(FTP)即使用流式套接字。

数据报式套接字(SOCK_DGRAM)• 提供一个无连接服务。

• 数据报以独立包形式被发送,不提供无错保证,数据可能丢失或重复,且接收顺序混乱。

• 网络文件系统(NFS)使用数据报式套接字。

原始式套接字(SOCK_RAW)• 该接口允许对较低层协议,如IP、ICMP直接访问。

• 常用于检验新的协议实现或访问现有服务中配置的新设备。

 • 服务方式面向连接(虚电路)• 面向连接服务是电话系统服务模式的抽象,每一次完整的数据传输都要经过建立连接、使用连接、终止连接的过程。

p o l l 方 法 的 基 本 概 念

p o l l 方 法 的 基 本 概 念

详细说说select poll epoll(以下内容来自网络和自己的总结,再次感谢网络中的大神们提供的见解)在探索select poll? epoll之前我们首先要知道什么叫多路复用:下来探索一下为什么会用到多路复用:首先我们看看一个客户端请求服务器的完整过程。

首先,请求过来,要建立连接,然后再接收数据,接收数据后,再发送数据。

具体到系统底层,就是读写事件,而当读写事件没有准备好时,必然不可操作,如果不用非阻塞的方式来调用,那就得阻塞调用了,事件没有准备好,那就只能等了,等事件准备好了,你再继续吧。

阻塞调用会进入内核等待,cpu就会让出去给其他进程使用了,你可能会说那么加进程数呀,当读写事件十分多的时候会创建很多的进程,此时进程的上下文切换会占用过多的cpu资-源。

有人会说那么用线程,其实线程的上下文切换也会占用过多资-源,而且还会引入线程之间同步和互斥的问题,因为线程之间看到的是同一块内存资-源。

所以我么就会思考能不能用一个进程来查看很多的IO事件,比如每一个人都在钓鱼每一个鱼上钩都比做是一个事件发生的话,那么一百个事件发生你可以让一百个人在那里一人拿一个鱼竿进行钓鱼,你自己负责进行鱼的收集。

此时如果没有鱼上钩,那一百个人就在那阻塞等待,你自己为了收鱼也在空闲着。

这里的你自己可以比作CPU,一般个人可以比作多个进程,此时如果不是所有鱼都上钩,你就十分空闲其他人也在那拿着鱼竿空闲等待着,如果同时有多个鱼上钩了,多个人会像你汇报,此时汇报的顺序问题就是形成混乱。

此时我们可以进行一下改进,比如专门找一个人拿着许多鱼竿,当一个鱼竿上的鱼上钩以后再拉起鱼竿,这样节约了人力,还解决了问题。

下来讲一个真实的故事吧:假设你是一个机场的空管,你需要管理到你机场的所有的航线,包括进港,出港,有些航班需要放到停机坪等待,有些航班需要去登机口接乘客。

你会怎么做?最简单的做法,就是你去招一大批空管员,然后每人盯一架飞机,从进港,接客,排位,出港,航线监控,直至交接给下一个空港,全程监控。

Windows网络编程系列教程之Select模型

Windows网络编程系列教程之Select模型

Windows网络编程系列教程之Select模型讲一下套接字模式和套接字I/O模型的区别。

先说明一下,只针对Winsock,如果你要骨头里挑鸡蛋把UNIX下的套接字概念来往这里套,那就不关我的事。

套接字模式:阻塞套接字和非阻塞套接字。

或者叫同步套接字和异步套接字。

套接字模型:描述如何对套接字的I/O行为进行管理。

Winsock提供的I/O模型一共有五种:select,WSAAsyncSelect,WSAEventSelect,Overlapped,Completion。

今天先讲解select。

1:select模型(选择模型)先看一下下面的这句代码:int iResult = recv(s, buffer,1024);这是用来接收数据的,在默认的阻塞模式下的套接字里,recv会阻塞在那里,直到套接字连接上有数据可读,把数据读到buffer里后recv函数才会返回,不然就会一直阻塞在那里。

在单线程的程序里出现这种情况会导致主线程(单线程程序里只有一个默认的主线程)被阻塞,这样整个程序被锁死在这里,如果永远没数据发送过来,那么程序就会被永远锁死。

这个问题可以用多线程解决,但是在有多个套接字连接的情况下,这不是一个好的选择,扩展性很差。

Select模型就是为了解决这个问题而出现的。

再看代码:int iResult = ioctlsocket(s, FIOBIO, (unsigned long *)&ul);iResult = recv(s, buffer,1024);这一次recv的调用不管套接字连接上有没有数据可以接收都会马上返回。

原因就在于我们用ioctlsocket把套接字设置为非阻塞模式了。

不过你跟踪一下就会发现,在没有数据的情况下,recv确实是马上返回了,但是也返回了一个错误:WSAEWOULDBLOCK,意思就是请求的操作没有成功完成。

看到这里很多人可能会说,那么就重复调用recv并检查返回值,直到成功为止,但是这样做效率很成问题,开销太大。

AB_RSLogix5000初级使用手册

AB_RSLogix5000初级使用手册

AB_RSLogix5000初级使用手册目录:设定笔记本IP地址 (3)查看PLC硬件组态信息 (3)设定RSLinx (4)打开RSLogix5000软件创建与RSLinx相符的程序 (7)在RSLogix5000软件中创建程序章节、程序段落、程序自然段 (10)上传和下载程序 (13)创建行参 (16)RSLinx查看网络IP以及硬件 (18)PLC静态和动态IP地址分配 (21)Firmware刷新 (25)Rxlogx5000软件的在线修改功能 (28)Rxlogx5000软件的在线强制功能 (31)范围指令LIM需要注意的是,当Low Limit < High Limit数值时,LIM命令在Low Limit和High Limit之间的数值时输出。

如果Low Limit > High Limit数值时,LIM命令在Low Limit和High Limit之间的数值时停止输出。

(35)查找跳转、中断等子程序块的位置 (35)RSLogix5000软件的在线帮组功能 (36)Routine里程序的类型 (37)一个Project里可以最多建立32个Task,但只能有一个Task属性为Continuous (连续扫描)其余的31个Task可以分配给Event(事件扫描)或者Periodic(中断扫描)。

每一个Task里可以建100个Program,每一个Program可以建立无穷个routine。

(38)备份程序和解压程序 (41)程序的比较 (43)Flash Memory Card 程序备份和下载操作 (46)模拟量模块的组态、量程设定、模拟量输出的钳位设定。

(49)Device Net网络配置 (53)Device Net软件安装 (55)Device Net组网 (57)在RSLogix5000程序里添加DeviceNet硬件 (69)DeviceNet的硬件寻址 (71)配置EtherNet以太网远程I/O (75)实时监控趋势图 (81)EDS文件更新 (85)设定笔记本IP地址1.查看AB_PLC机器槽架上的CPU模块显示的IP地址,一般PLC的IP地址为为10.0.0.1,笔记本上的IP最后一位设置需要变化。

Socket编程模型之完成端口模型

Socket编程模型之完成端口模型

Socket编程模型之完成端口模型一、回顾重叠IO模型用完成例程来实现重叠I/O比用事件通知简单得多。

在这个模型中,主线程只用不停的接受连接即可;辅助线程判断有没有新的客户端连接被建立,如果有,就为那个客户端套接字激活一个异步的WSARecv操作,然后调用SleepEx使线程处于一种可警告的等待状态,以使得I/O完成后CompletionROUTINE可以被内核调用。

如果辅助线程不调用SleepEx,则内核在完成一次I/O操作后,无法调用完成例程(因为完成例程的运行应该和当初激活WSARecv异步操作的代码在同一个线程之内)。

完成例程内的实现代码比较简单,它取出接收到的数据,然后将数据原封不动的发送给客户端,最后重新激活另一个WSARecv异步操作。

注意,在这里用到了“尾随数据”。

我们在调用WSARecv的时候,参数lpOverlapped实际上指向一个比它大得多的结构PER_IO_OPERATION_DATA,这个结构除了WSAOVERLAPPED以外,还被我们附加了缓冲区的结构信息,另外还包括客户端套接字等重要的信息。

这样,在完成例程中通过参数lpOverlapped拿到的不仅仅是WSAOVERLAPPED结构,还有后边尾随的包含客户端套接字和接收数据缓冲区等重要信息。

这样的C语言技巧在我介绍完成端口的时候还会使用到。

二、完成端口模型“完成端口”模型是迄今为止最为复杂的一种I/O模型。

然而,假若一个应用程序同时需要管理为数众多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但不幸的是,该模型只适用于Windows NT和Windows 2000操作系统。

因其设计的复杂性,只有在你的应用程序需要同时管理数百乃至上千个套接字的时候,而且希望随着系统内安装的CPU数量的增多,应用程序的性能也可以线性提升,才应考虑采用“完成端口”模型。

要记住的一个基本准则是,假如要为Windows NT或Windows 2000开发高性能的服务器应用,同时希望为大量套接字I/O请求提供服务(Web服务器便是这方面的典型例子),那么I/O完成端口模型便是最佳选择!完成端口模型是我最喜爱的一种模型。

简述iocp模型的原理和工作过程

简述iocp模型的原理和工作过程

简述iocp模型的原理和工作过程IOCP(Input/Output Completion Port)模型是一种高效的异步IO 机制,它可以帮助我们更好地处理并发IO请求。

在本文中,我们将详细介绍IOCP模型的原理和工作过程。

一、IOCP模型的基本原理1.1 异步IO在传统的同步IO模型中,当程序调用一个IO操作时,它必须等待该操作完成后才能继续执行后面的代码。

这种方式会导致程序在等待IO 操作完成时出现阻塞,从而浪费了CPU资源。

相比之下,异步IO模型允许程序调用一个IO操作后立即返回,并在后台处理该操作。

当该操作完成时,系统将通知程序,并返回结果。

这种方式可以提高程序的并发性和吞吐量。

1.2 IOCP机制为了更好地支持异步IO,Windows引入了IOCP机制。

它是一种通知机制,可以帮助我们更好地处理异步IO请求。

具体来说,当一个异步IO请求被提交到系统中时,系统会为其分配一个I/O Completion Port(即完成端口)。

当该请求完成时,系统将通知该端口,并返回相关信息。

程序可以通过监听该端口来获取请求完成的通知,并进行相应的处理。

二、 IOCP模型的工作过程2.1 创建I/O Completion Port首先需要创建I/O Completion Port(以下简称IOCP)。

可以通过CreateIoCompletionPort函数来创建一个IOCP。

该函数返回一个句柄,该句柄用于后续的操作。

2.2 将Socket与IOCP关联接下来需要将Socket与IOCP关联。

可以通过CreateIoCompletionPort或者WSAEventSelect函数来实现。

2.3 提交异步IO请求当需要进行异步IO操作时,可以使用WSASend、WSARecv等函数来提交异步IO请求。

这些函数会将请求提交到系统中,并立即返回。

2.4 处理完成通知当一个异步IO请求完成时,系统会向其关联的IOCP发送一个完成通知。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

手把手教你玩转网络编程模型之完成例程(Completion Routine)篇----- By PiggyXP(小猪)前言记得写这个系列的上一篇文章的时候已经是四年前了,准确的说是四年半以前了,翻开我尘封已久的blog,感觉到上面已经落了厚厚的一层尘土,突然又来了感觉,于是我翻箱倒柜的找出以前的资料,上传到了我的空间里,而且,顺便又为在网络编程苦海中苦苦寻觅的朋友带来一份礼物,这次为大家带来的是重叠IO模型里面的“完成例程”的实现方式及示例代码。

本文凝聚着笔者心血,如要转载,请指明原作者及出处,谢谢!不过代码写得不好,欢迎改进,而且没有版权,请随便散播、使用。

^_^OK, Let’s go ! Have fun!!本文配套的示例源码下载地址(在我的下载空间里)/user/PiggyXP(VC++ 2008编写的多客户端MFC代码,配有非常非常详尽的注释,功能只是简单的显示一下各个客户端发来的字符,作为教学代码,为了使得代码结构清晰明了,简化了很多地方,用于产品开发的话还需要做很多改进,有错误或者不足的地方,非常欢迎大家不吝指出。

)代码界面示意图:本文假设你已经对重叠I/O的机制已有了解,否则请先参考本系列的前一篇《手把手教你玩转重叠IO模型》目录:1.完成例程的优点2.完成例程的基本原理3.关于完成例程的函数介绍4.完成例程的实现步骤5.实际应用中应该进一步完善的地方一.完成例程的优点1.首先需要指明的是,这里的“完成例程”(Completion Routine)并非是大家所常听到的“完成端口”(CompletionPort),而是另外一种管理重叠I/O请求的方式,而至于什么是重叠I/O,简单来讲就是Windows系统内部管理I/O 的一种方式,核心就是调用的ReadFile和WriteFile函数,在制定设备上执行I/O操作,不光是可用于网络通信,也可以用于其他需要的地方。

在Windows系统中,管理重叠I/O可以有三种方式:(1) 上一篇中提到的基于事件通知的重叠I/O模型(2) 本篇中将要讲述的基于“完成例程”的重叠I/O模型(3) 下一篇中将要讲到的“完成端口”模型虽然都是基于重叠I/O,但是因为前两种模型都是需要自己来管理任务的分派,所以性能上没有区别,而完成端口是创建完成端口对象使操作系统亲自来管理任务的分派,所以完成端口肯定是能获得最好的性能。

2.如果你想要使用重叠I/O机制带来的高性能模型,又懊恼于基于事件通知的重叠模型要收到64个等待事件的限制,还有点畏惧完成端口稍显复杂的初始化过程,那么“完成例程”无疑是你最好的选择!^_^ 因为完成例程摆脱了事件通知的限制,可以连入任意数量客户端而不用另开线程,也就是说只用很简单的一些代码就可以利用Windows内部的I/ O机制来获得网络服务器的高性能,是不是心动了呢?那就一起往下看。

3.而且个人感觉“完成例程”的方式比重叠I/O更好理解,因为就和我们传统的“回调函数”是一样的,也更容易使用一些,推荐!二.完成例程的基本原理概括一点说,上一篇拙作中提到的那个基于事件通知的重叠I/O模型,在你投递了一个请求以后(比如WSARecv),系统在完成以后是用事件来通知你的,而在完成例程中,系统在网络操作完成以后会自动调用你提供的回调函数,区别仅此而已,是不是很简单呢?首先这里统一几个名词,包括“重叠操作”、“重叠请求”、“投递请求”等等,这是为了配合这的重叠I/O才这么讲的,说的直白一些,也就是你在代码中发出的WSARecv()、WSASend()等等网络函数调用。

上篇文章中偷懒没画图,这次还是画个流程图来说明吧,采用完成例程的服务器端,通信流程简单的来讲是这样的:从图中可以看到,服务器端存在一个明显的异步过程,也就是说我们把客户端连入的SOCKET与一个重叠结构绑定之后,便可以将通讯过程全权交给系统内部自己去帮我们调度处理了,我们在主线程中就可以去做其他的事情,边等候系统完成的通知就OK,这也就是完成例程高性能的原因所在。

如果还没有看明白,我们打个通俗易懂的比方,完成例程的处理过程,也就像我们告诉系统,说“我想要在网络上接收网络数据,你去帮我办一下”(投递WSARecv操作),“不过我并不知道网络数据何时到达,总之在接收到网络数据之后,你直接就调用我给你的这个函数(比如_CompletionProess),把他们保存到内存中或是显示到界面中等等,全权交给你处理了”,于是乎,系统在接收到网络数据之后,一方面系统会给我们一个通知,另外同时系统也会自动调用我们事先准备好的回调函数,就不需要我们自己操心了。

看到这里,各位应该已经对完成例程的体系结构有了比价清晰的了解了吧,下面各位喝点咖啡转转脖子休息休息,然后就进入到下面的具体实现部分了。

一.完成例程的函数介绍这个部分将要介绍在完成例程模型中会使用到的关键函数,内容比较枯燥,大家要做好心理准备。

不过在实际应用以前,很多东西肯定也不会理解得太深刻,可以先泛泛的了解一下,以后再回头复习这里的知识就可以了。

厄。

仔细审查了一下代码,发现其实这里也没有什么新函数好介绍了,大部分都是使用重叠模型那一章里介绍的一样的函数,需要查看的朋友请看这里《手把手教你玩转重叠IO模型》,这里就不再重复了:这里只补充一个知识点,就是咱们完成例程方式和前面的事件通知方式最大的不同之处就在于,我们需要提供一个回调函数供系统收到网络数据后自动调用,回调函数的参数定义应该遵照如下的函数原型:1.完成例程回调函数原型及传递方式函数应该是这样定义的,函数名字随便起,但是参数类型不能错Void CALLBACK _CompletionRoutineFunc(DWORD dwError, // 标志咱们投递的重叠操作,比如WSARecv,完成的状态是什么DWORD cbTransferred, // 指明了在重叠操作期间,实际传输的字节量是多大LPWSAOVERLAPPED lpOverlapped, // 参数指明传递到最初的IO调用内的一个重叠结构DWORD dwFlags // 返回操作结束时可能用的标志(一般没用));还有一点需要重点提一下的是,因为我们需要给系统提供一个如上面定义的那样的回调函数,以便系统在完成了网络操作后自动调用,这里就需要提一下究竟是如何把这个函数与系统内部绑定的呢?如下所示,在WSARecv函数中是这样绑定的int WSARecv(SOCKET s, // 当然是投递这个操作的套接字LPWSABUF lpBuffers, // 接收缓冲区,与Recv函数不同// 这里需要一个由WSABUF结构构成的数组DWORD dwBufferCount, // 数组中WSABUF结构的数量,设置为1即可LPDWORD lpNumberOfBytesRecvd, // 如果接收操作立即完成,这里会返回函数调用// 所接收到的字节数LPDWORD lpFlags, // 说来话长了,我们这里设置为0 即可LPWSAOVERLAPPED lpOverlapped, // “绑定”的重叠结构LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine// 我们的完成例程函数的指针);其他参数我们可以先不用先细看,只看最后一个,看到了吗?直接在WSARecv的最后一个参数上,传递一下我们回调函数的指针就行了,这里注意一下,咱们这次多次提到的这个“完成例程”,其实就是指的咱们提供的这个回调函数。

举个例子:(变量的定义顺序和上面的说明的顺序是对应的,下同)SOCKET s;WSABUF DataBuf; // 定义WSABUF结构的缓冲区// 初始化一下DataBuf#define DATA_BUFSIZE 4096char buffer[DATA_BUFSIZE];ZeroMemory(buffer, DATA_BUFSIZE);DataBuf.len = DATA_BUFSIZE;DataBuf.buf = buffer;DWORD dwBufferCount = 1, dwRecvBytes = 0, Flags = 0;// 建立需要的重叠结构,每个连入的SOCKET上的每一个重叠操作都得绑定一个WSAOVERLAPPED AcceptOverlapped ;// 如果要处理多个操作,这里当然需要一个// WSAOVERLAPPED数组ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));// 作了这么多工作,终于可以使用WSARecv来把我们的完成例程函数绑定上了// 当然,假设我们的_CompletionRoutine函数已经定义好了WSARecv(s, &DataBuf, dwBufferCount, &dwRecvBytes, &Flags, &AcceptOverlapped, _CompletionRoutine);其他的函数我这里就不一一介绍了,因为我们毕竟还有MSDN这么个好帮手,而且在讲后面的完成例程和完成端口的时候我还会讲到一些^_^四.完成例程的实现步骤基础知识方面需要知道的就是这么多,下面我们配合代码,来一步步的讲解如何亲手实现一个完成例程模型(前面几步的步骤和基于事件通知的重叠I/O方法是一样的)。

【第一步】创建一个套接字,开始在指定的端口上监听连接请求和其他的SOCKET初始化全无二致,直接照搬即可,在此也不多费唇舌了,需要注意的是为了一目了然,我去掉了错误处理,平常可不要这样啊,尽管这里出错的几率比较小。

WSADATA wsaData;WSAStartup(MAKEWORD(2,2),&wsaData);ListenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //创建TCP套接字SOCKADDR_IN ServerAddr; //分配端口及协议族并绑定ServerAddr.sin_family=AF_INET;ServerAddr.sin_addr.S_un.S_addr =htonl(INADDR_ANY);ServerAddr.sin_port=htons(11111); // 在11111端口监听// 端口号可以随意更改,但最好不要少于1024 bind(ListenSocket,(LPSOCKADDR)&ServerAddr, sizeof(ServerAddr)); // 绑定套接字listen(ListenSocket, 5); //开始监听【第二步】接受一个入站的连接请求一个accept就完了,都是一样一样一样一样的啊~~~~~~~~~~至于AcceptEx的使用,在完成端口中我会讲到,这里就先不一次灌输这么多了,不消化啊^_^AcceptSocket = accept (ListenSocket, NULL,NULL) ;当然,这里是我偷懒,如果想要获得连入客户端的信息(记得论坛上也常有人问到),accept的后两个参数就不要用NULL,而是这样SOCKADDR_IN ClientAddr; // 定义一个客户端得地址结构作为参数int addr_length=sizeof(ClientAddr);AcceptSocket = accept(ListenSocket,(SOCKADDR*)&ClientAddr, &addr_length);// 于是乎,我们就可以轻松得知连入客户端的信息了LPCTSTR lpIP = inet_ntoa(ClientAddr.sin_addr); // 连入客户端的IPUINT nPort = ClientAddr.sin_port; // 连入客户端的Port【第三步】准备好我们的重叠结构有新的套接字连入以后,新建立一个WSAOVERLAPPED重叠结构(当然也可以提前建立好),准备绑定到我们的重叠操作上去。

相关文档
最新文档