winsocket的同步阻塞结合多线程方便简单设计节点服务器,但是真要弄出个高效并发的服务器还得考虑下异步阻塞或非阻塞机制。winsocket引入了几个套接字I/O模型,分别如下:
1.select模型:避免了异步机制实时返回WSAEWOULDBLOCK 的错误(无功而返),该方法通过定义套接字、套接字集合变量,循环清除套接字集合变量、将套接字添加至集合,使用select函数选择符合参数规定条件的套接字,保留符合条件的套接字删除不符合条件的,依据其返回值判断所定义的套接字是否还在套接字集合里边,如果在则说明选到了符合条件的套接字,可对该套接字进行操作。
2.WSAAsyncSelect异步I/O模型:利用windows的消息机制,使用WSAAsyncSelect()函数,通过指定套接字上感兴趣的网络事件,一旦该网络事件发生,发送指定消息到窗体,窗体回调函数接受该消息并处理该套接字上的事件(连接请求、读取数据、发送数据、关闭套接字)。
3.WSAEventSelect事件选择模型:他和WSAAsyncSelect模型类似,他也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知,差别在于网络事件会投递至一个事件对象句柄,而非投递至一个窗口例程。
4.重叠I/O模型:重叠模型的基本原理是让应用程序使用一个重叠的数据结构,一次投递一个或者多个Winsock的I/O请求,针对那些提交的请求,在他们完成之后,用用程序可以为他们提供服务,有事件通知和完成例程(回调函数)两种方式。其步骤为:
事件通知方式:
1.定义变量. 包括套接字,重叠变量,事件数组.
2.创建监听套接字,绑定地址,在制定的端口上监听连接请求.
3.接受一个客服端的连接请求accept();
4.创建事件数组,初始化重叠结构,关联事件(重叠结构关联的事件),buffer初始化。
5.以WSAOVERLAPPED结构为参数,在套接字上投递WSARecv请求。
6.调用WSAWaitForMultipleEvents函数,等待重叠操作返回的结果。
7.使用WSAResetEvent函数重设当前这个用完的事件对象。
8.使用WSAGetOverlappedResult函数取得重叠调用的返回状态。
9.使用接受的数据,buffer结构里接受到了数据可使用。
10.回到第5,在套接字上继续投递WSARecv请求,重复步骤6-9.
完成例程处理(回调函数处理)方式:
1.新建一个监听套接字,在制定的端口监听客户端的连接请求。
2.接受一个客户端的连接请求,并返回一个会话套接字负责与客户端的连接请求。
3.为会话套接字关联一个WSAOVERLAPPED结构。
4.在套接字上投递一个异步WSARecv请求,方法是将WSAOVERLAPPED指定成为参数,同时提供一个完成例程。
5.在将falertable参数设为TURE的前提下,调用WSAWaitForMultipleEvents,并等待一个重叠I/O请求完成。重叠请求完成后, 完成例程会自动执行,而且WSAWaitForMultipleEvents会返回一个WAIT_IO_COMPLITION.在完成例程内,可随一个完成例程一道投递另一个重叠WSARecv请求。
6.检查WSAWaitForMultipleEvents是否返回WAIT_IO_COMPLIETION.
7.重复步骤 5--6.
重叠IO模型的缺点是为每一个IO请求都开了一个线程,当同时有成千上万个请求发生时,系统处理线程上下文切换是非常耗时的。所以这也就引出了先进的完成端口模型IOCP.用线程池来解决这个问题。
5.完成端口(IOCP)模型:
完成端口IO模型是应用程序使用线程池处理异步IO请求的一种机制。首先创建一个win32完成端口对象,再创建一定数量的工作线程,应用程序发出一些异步IO请求,当这些请求完成时,系统将把这些工作项目安排到完成端口,这样,在完成端口上等待的线程池便可以处理这些完成的IO,为已经完成的重叠IO请求提供服务。所谓的完成端口是一个windowsI/O结构,可以接受多种I/O对象的句柄,如文件对象,套接字对象等。
IOCP的基本步骤:
1.调用CreatIoCompletionPort函数,创建一个完成端口。忽略前三个参数,第四个参数为零,旨在创建一完成端口对象,同时指定在完成端口上,每个处理器一次只允许执行一个工作者线程。
2.判断系统内到底安装了多少个处理器。
3.创建工作者线程,在完成端口上,为已完成的IO请求提供服务(调用GetQueuedCompletionStatus()注意单句柄数据和单I/O操作数据的使用)。
4.监听套接字--->绑定---->监听
5.使用accept函数,接受进入的连接请求。
6.创建一个数据结构,用于容纳"单句柄数据",同时在结构中存入接受的套接字句柄。
7.再次调用CreatIoCompletionPort函数,将自accept返回的新套接字句柄同完成端口关联到一起。通过完成键(CompletionKey)参数,将单句柄数据结构传递给函数。
8.开始在已接受的连接上进行io操作。通过重叠io机制,在新建的套接字上投递一个或者多个异步WSARecv或者WSASend请求。这些io请求完成后,一个工作线程会为io请求提供服务。同时继续处理未来的io请求。
9.重复 5-- 8 至终止。分别于主线程循环阻塞accept() ;于工作线程循环阻塞GetQueuedCompletionStatus();
不停地发出异步的WSASend/WSARecv IO操作,具体的io处理过程由windows系统完成,WINDOWS系统完成实际的io处理后,把结果送到完成端口上。如果有多个io都完成了那么就在完成端口那里排成一个队列。在另外一个线程里从完成端口不断地取出io操作结果,然后根据需要在发出WSASend/WSARecv IO 操作。
IOCP模型最大的特色是:线程的服务单位被分割了,从传统的以用户为服务单位转为以IO操作为服务单位。