前面已经说过 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 可以传递一个 WSAPROTOCOL_INFO 结构体的地址,其中包含创建套接字的信息,不使用时传入 NULL;g 是作为扩展函数而预约的参数,也为 NULL 便好;dwFlags 表示套接字的标志,要使用重叠 IO,得设为 WSA_FLAG_OVERLAPPED。… Continue Reading 网络模型之重叠IO(一)

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

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