• windows网络模型


    Windows提供了四种异步IO技术,机制几乎时相同的,区别在于通知结果的方式不同:

    1、通过注册的消息函数进行通知

    2、通过内核event事件进行通知

    3、通过称为完成例程的回调函数进行通知

    4、通过完成端口进行通知

    WSAAsyncSelect

    过程:创建一个套接字后,调用WSAAsyncSelect函数对该套接字注册感兴趣的网络事件,例如accept,read,write等,并且注册对应的Windows 消息,当然要先定义好消息响应函数,这样当某个注册的socket有消息时,就会主动去调用消息响应函数,该函数首先去判断发生了什么网络消息,以及是哪个socket发生了消息,然后调用socket对应的函数进行处理完成了。

    与select的区别

    1、select函数是阻塞的,WSAAsyncSelect是非阻塞的,当没有网络消息时,select会一直阻塞在该函数这里,WSAAsyncSelect则不会。

    2、select是同步的,WSAAsyncSelect是异步的,因为WSAAsyncSelect在有消息响应时会自动去调用消息响应函数,相当于异步的回调函数。

    3、WSAAsyncSelect是基于Windows消息的,参数也需要窗口句柄,需要依赖窗口的存在,所以mfc中的封装类CSocket和CAsyncSocket就是基于WSAAsyncSelect实现的。select是不需要窗口句柄的。

    4、socket被WSAAsyncSelect注册之后,自动变为非阻塞的。而select里的socket还是阻塞的。

    5、select和WSAAsyncSelect所能处理的socket数目是可以调整的,select可以调整FD_SIZE来改变数目,WSAAsyncSelect只要消息能响应及时就没问题。

    WSAEventSelect

    过程:每得到一个新的socket,调用WSACreateEvent就创建一个内核事件,然后调用WSAEventSelect将该内核事件与socket绑定起来,用两个数组,一个用来存储socket,一个用来存储对应的event,位置要一一对应,创建好之后调用WSAWaitForMultipleEvents来等待event数组,有event事件时,该函数返回有消息事件在数组中的索引,根据索引得到有消息的socket和event,并判断出是发生了什么网络消息,然后再进行处理就可以了。

    说明

    1、该模型是基于event内核事件的,因此不像基于WSAAsyncSelect基于消息那样需要有窗口才行。

    2、调用WSAEventSelect之后,socket也是变为非阻塞的。

    3、受WSAWaitForMultipleEvents的限制,该函数一次最多只能处理64个事件对象。因此如果想要多于这个数目,一种方法是加开线程.

     

    重叠IO

    过程:得到一个新的socket连接时,为该socket创建一个重叠IO和event事件,绑定起来,然后用WSARecv投递调用,调用WSAWaitForMultipleEvents函数等待与重叠IO关联在一起的事件变为已触发状态,WSAWaitForMultipleEvents返回后,调用WSAResetEvent函数,将该事件对象恢复为未触发态。调用WSAGetOverlappedResult函数判断重叠IO的完成状态。处理完之后重新调用WSARecv投递请求。上面是通过事件通知的过程,也可以完成例程即在WSARecv中注册回调函数来完成消息通知。

    说明

    1、重叠IO延续了win32 IO模型。从发送和接收的角度来看,重叠IO模型与前面介绍的Select模型、WSAAsyncSelect模型和WSAEventSelect模型都不同。因为在这三个模型中IO操作还是同步的,例如:在应用程序调用recv函数时,都会在recv函数内阻塞,直到接收数据完毕后才返回。而重叠IO模型会在调用recv后立即返回。等数据准备好后再通知应用程序。

    2、系统向应用程序发送通知的形式有两种:一是事件通知。二是完成例程。后面将会介绍这两种形式。

    3、在Windows socket中,接收数据的过程可以分为:等待数据和将数据从系统复制到用户空间两个阶段。各种IO模型的区别在于这两个阶段上。

    前三个模型的第一个阶段的区别: select模型利用select函数主动检查系统中套接字是否满足可读条件。WSAAsyncSelect模型和WSAEventSelect模型则被动等待系统的通知。

    第二个阶段的区别:此阶段前三个模型基本相同,在将数据从系统复制到用户缓冲区时,线程阻塞。而重叠IO与它们都不同,应用程序在调用输入函数后,只需等待接收系统完成的IO操作完成通知。

     

    iocp

    过程

    1、创建一个服务线程,调用WSASocket创建监听套接字,并完成固定的初始化过程,使用WSAAccept开始监听,开始监听

    2、事先调用CreateIoCompletionPort创建一个完成端口,当收到请求socket之后,在调用这个函数将它加入到完成端口队列中,

    3、加入之后,还要为该socket创建一个接收的重叠IO和缓存,然后通过WSARecv函数将套接字,重叠IO和缓存一起投递出去

    4、上面就是服务线程的处理流程,接下来开启多个工作线程,来处理每个连接

    5、在工作者线程中,调用GetQueuedCompletionStatus函数不断查询各IO状态,当有IO有消息时,该函数返回,并返回有消息的IO和套接字,拿出数据之后,对IO进行初始化之后,再通过WSARecv函数把这个IO投递进去准备接收下一个网络消息。

    说明

    1、这里的异步在于把一个分配了重叠IO和缓存空间的socket放进IOCP之后,就不需要对这个连接进行专门的处理,接下里就是通用的操作,不断的查询IOCP队列里各连接的状态,当IOCP在系统内部完成数据处理,把数据放到该连接的缓存空间之后,才发出消息通知,然后端口函数把重叠IO从队列中取出,得到里面的数据处理,然后清空数据,再把这个重叠投递到队列里,接收下一次的消息。

    2、使用重叠IO可以直接得到数据,避免了阻塞recv中将数据从系统空间复制到用户空间这一阻塞过程。这只是它效率高的一个因素,它还维护一个队列,来自动监控是否有消息到来,每个线程能处理的队列的数目是没有限制,要看实际效果而定,同时灵活方便扩展线程,用一个线程或几个线程都可以,当然线程数目也要考虑到CPU的数目。并且重叠IO利用事件通知时,每个线程有64的限制,使用完成例程的回调函数,这样多线程的优势就得不到利用。

     

     

  • 相关阅读:
    Windows系统之间文件互传
    PHP MySQL -2021.01.30
    Python MySQL
    [转载]python之函数的使用及异常处理2021.1.30
    python之文件操作
    Python学习-2021.1.28
    [转载]Metasploit漏洞攻击
    [转载]使用命令给windows用户提权
    [转载]nmap的使用
    Windows和Linux简单命令的总结
  • 原文地址:https://www.cnblogs.com/suntp/p/6483700.html
Copyright © 2020-2023  润新知