前面已经说过 select 和 Event selct 模型,这两个还是比较小型的,今天来说重叠 IO,这个可以支持上千个用户,当然理解起来也越来越难了点。 重叠 IO 模型是典型的非阻塞模型,接收数据和拷贝数据这两部分全部占用系统时间片,实现了效率最大化,只要将一个结构体投给系统它便会替我们完成耗时的处理。 首先来看如何创建一个支持重叠 IO 的套接字,使用的是 WSASocket 函数,原型如下: SOCKET WSASocket ( int af, // 地址族 int type, // 传输方式 int protocol, // 通信协议 LPWSAPROTOCOL_INFO lpProtocolInfo, GROUP g, DWORD dwFlags ); 前3个参数就是以前使用的 socket 函数的参数,主要来看后面的几个参数。lpProtocolInfo… Continue Reading

开始之前,再来看看流程图。 程序阻塞的主要有两部分,一个是等待数据到来,一个是将数据从内核复制到程序缓冲区。 事件选择模型,其实是在 select 模型的基础上更进一步地做了优化,这次优化把等待数据到来的这部分变成了非阻塞。而这主要是使用 WSAEventSelect 函数完成的,其原型如下: int WSAEventSelect ( SOCKET s, // 套接字 WSAEVENT hEventObject, // 事件对象 long lNetworkEvents // 网络事件 ); 事件选择给每个套接字绑定了一个事件,当发生指定网络事件的时候它会把绑定的事件变为 signaled 状态。 WSAEVENT 其实和之前在 Windows 线程同步中所说的内核对象事件是一样的,只是在这个函数中需要手动重置事件,为了清晰方便,所以弄了个 typedef,并提供了一个 WSACreateEvent 函数来创建手动重置的事件。 WSAEVENT event = WSACreateEvent(); 其实,这个 WSACreateEvent 函数就相当于调用以下语句:… Continue Reading

之前我们写了一些简单的网络程序,使用的都是基本的socket,这些程序有一个特点就是都是阻塞执行的。何谓阻塞呢?就是函数不会立即返回,直到等到结果才返回,像 accept,recv 就属于阻塞函数。 这种方式在人数(客户端)较少的情境下没有什么问题,但要是人数比较多了服务器就不能及时处理后面的客户请求了。若第一个连接的用户受理时间为 1 秒,那么第一百个连接的用户就得等 100秒。一个方法是可以为每个连接进来的用户开启一个线程进行处理,但开启太多的线程得付出很大的代价,所以这种方式也仅适用于用户较少的情况。 基于此,Windows 提供了一些网络模型来提高服务器同时接受客户端的能力。这里将会以几篇来分别讲解几个常用的模型: select 事件选择 重叠 IO IOCP 完成端口 这些模型从弱到强,从易到难。select 用来解决基本 socket 多线程的问题,适合 60 多个用户。事件选择异步了接受操作,适合 300-500 个用户。重叠 IO 就完全非阻塞了,适合上千个用户。IOCP 更加强大,可以支持万级别的用户,QQ 那些就使用的这个。 还有 Linux 上的 epoll 模型,这个和 IOCP 是一个级别的,因为我没怎么接触 Linux,所以这里就主要说 Windows 上的。 这里首先来说最简单的 select 模型,在此之前,我先画了一张图:… Continue Reading