当前位置:首页 > Windows程序 > 正文

Windows 非阻塞或异步 socket

2021-03-28 Windows程序

异步与非阻塞区别见我的另外一篇文章Socket 同步/异步与阻塞/非阻塞区别

select

WSAAsyncSelect

WSAEventSelect

重叠(Overlapped)I/O

IOCP:完成端口

Select

首先要使用ioctlsocket设置为非阻塞模式。

然后启动线程,线程中不停select。

WSAAsyncSelect

WSAAsyncSelect模型是Windows下最简单易用的一种Socket I/O模型。使用这种模型时,Windows会把网络事件以消息的形势通知应用程序。此模型提供了读写数据能力的异步通知,但不提供异步数据传送。需要在消息响应函数里send(一般为resend)和receive。由于该模型基于Windows消息机制,必须在应用程序中创建窗口。虽然可以在开发中,确定是否显示该窗口。 

WSAEventSelect

通常与WSACreateEvent、WSAResetEvent、WSACloseEvent、WSAWaitForMultileEvents和WSAEnumNetworkEvents一起使用,无需创建窗口。WSAWaitForMultileEvents检查是否有Event,WSAEnumNetworkEvents枚举事件类型,FD_READ、FD_WRITE等。

函数最多可以支持WSA_MAXIMUM_WAIT_EVENTS(64)个对象.该函数会等待网络事件的发生,如果过了指定了时间(dwTimeOut)则返回WSA_WAIT_TIMEOUT,如果在规定的时间内有事件发生,则返回该事件对象的索引(注意:在程序中要想得到发生的事件的真正索引需得用返回值减去WSA_WAIT_EVENT_0),调用失败返回WSA_WAIT_FAILED.如果将参数fWaitAll设置成false如果有多个网络事件发生该函数也只返回一个事件对象索引,并且该事件是在事件句柄数组中最前面的一个.解决方法是循环调用该函数处理后面的受信事件. 

重叠(Overlapped)I/O

它和之前模型不同的是,使用重叠模型的应用程序通知缓冲区收发系统直接使用数据,也就是说,如果应用程序投递了一个10KB大小的缓冲区来接收数据,且数据已经到达套接字,则该数据将直接被拷贝到投递的缓冲区。之前的模型都是在套接字的缓冲区中,当通知应用程序接收后,在把数据拷贝到程序的缓冲区。

——摘自

以receive为例,之前的模型,需要自己从套接字的缓冲区拷贝至程序缓冲区,而重叠IO则是操作系统直接将数据拷贝至程序缓冲区。

重叠模型的核心是一个重叠数据结构。若想以重叠方式使用文件,必须用 FILE_FLAG_OVERLAPPED标志打开它。

有2种方式实现:

1. 事件

先WaitForSingleObject/WaitForMultipleObjects或WSAWaitForMultipleEvents函数 ,然后调用(WSA)GetOverlappedResult()函数,最后,使用指针偏移定位就可以准确操作接受到的数据了。

与其他事件类似,,最大个数为64.

2. 完成例程(非完成端口)

ReadFileEx(),传递回调函数指针。

完成端口

所谓“完成端口",实际是Win32 、Windows NT以及Windows 2000采用的一种I / O构造机制,除套接字句柄之外,实际上还可接受其他东西(重叠IO好像也可以)。

使用这种模型之前,首先要创建一个 I / O 完成端口对象(CreateIoCompletionPort),

NumberOfConcurrentThread参数的特殊之处在于,它定义了在一个完成端口上,同时允许执行的线程数量。理想情况下,我们希望每个处理器各自负责一个线程的运行,为完成端口提供服务,避免过于频繁的线程“场景”切换。若将该参数设为 0,表明系统内安装了多少个处理器,便允许同时运行多少个线程!

1)  创建一个完成端口。第四个参数保持为 0,指定在完成端口上,每个处理器一次只允许执行一个工作者线程。

2)  判断系统内到底安装了多少个处理器。

3)  创建工作者线程,根据步骤 2 )得到的处理器信息,在完成端口上,为已完成的 I / O请求提供服务。在这个简单的例子中,我们为每个处理器都只创建一个工作者线程。这是由于事先已预计到,到时不会有任何线程进入“挂起”状态,造成由于线程数量的不足,而使处理器空闲的局面(没有足够的线程可供执行) 。调用C r e a t e T h r e a d函数时,必须同时提供一个工作者例程,由线程在创建好执行。本节稍后还会详细讨论线程的职责。

4)  准备好一个监听套接字,在端口 5 1 5 0上监听进入的连接请求。

5) 使用a c c e p t函数,接受进入的连接请求。

6)  创建一个数据结构,用于容纳“单句柄数据” ,同时在结构中存入接受的套接字句柄。

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/69102.html