1 / 16

异步 IO

异步 IO. 计算机网络实验课. 两种模式. 阻塞模式 非阻塞模式. 阻塞模式. 套接字创建时,默认工作在阻塞模式下。例如对于 recv 函数的调用会使程序进入等待状态,直到接收到数据才返回 使用阻塞模式时,需要处理多个套接字连接时,就必须创建多个线程,即一个连接使用一个线程 One thread per client 阻塞模式为什么一定是 One thread per client ? 考虑一个线程正在等待接收数据,却有别的客户在申请连接。。。. One thread per client. 优点

chyna
Download Presentation

异步 IO

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 异步IO 计算机网络实验课

  2. 两种模式 • 阻塞模式 • 非阻塞模式

  3. 阻塞模式 • 套接字创建时,默认工作在阻塞模式下。例如对于recv函数的调用会使程序进入等待状态,直到接收到数据才返回 • 使用阻塞模式时,需要处理多个套接字连接时,就必须创建多个线程,即一个连接使用一个线程 • One thread per client • 阻塞模式为什么一定是One thread per client? • 考虑一个线程正在等待接收数据,却有别的客户在申请连接。。。

  4. One thread per client • 优点 • 简单,并且在用户数量为a few tens的时候,是响应速度最快的一种模型 • 缺点 • 扩展性不好 1)每一个线程都要消耗系统资源 2)系统在线程间切换需要花费时间 • 当more than a few tens的线程同时运行时,因素2)首先影响系统性能,线程进一步增加时,因素1)的作用也会越来越明显

  5. Thread的理论值 • 从资料来看,每一个线程默认分配的堆栈是1M • 每一个用户进程最大的可用地址空间是2G • 所以理论上默认的线程数量是2000 • 限制堆栈大小之后,例如4K,出现了另外一个地址空间分配粒度的问题,最小为64K,所以最多线程数约13000. 注意到还有一些系统DLL等需要占用内存

  6. 阻塞模式小结 • One thread per client • 主要问题是系统性能受影响 • 线程的数量限制不是主要因素 • 为了开发高效的服务器程序,我们需要使用非阻塞模式

  7. 非阻塞模式 • 非阻塞模式下,执行I/O的函数调用send和recv会马上返回 • 大多数情况下,调用后返回的是出错代码 WSAWOULDBLOCK,该代码意味着请求的操作在调用期间没有完成 • 例如,系统输入缓存中没有待处理的数据,那么执行recv会返回WSAWOULDBLOCK

  8. 非阻塞模式 • 关键的问题在于确定套接字什么时候可读可写,或者说确定套接口上的可读可写网络事件何时发生。。。 • 可以使用Winsock提供的各种不同的I/O模型

  9. 非阻塞小结 • 结合对One thread per client的讨论,我们看到非阻塞模式主要解决的问题在于 • 如何在使用尽量少的线程的条件下,接受尽可能多的并发用户连接。。。

  10. 异步I/O——Select-1 • 使用了一个数据结构 typedef struct fd_set { u_int fd_count; SOCKET fd_array[FD_SETSIZE]; } fd_set; • 其中fd_count指名了fd_array中有多少套接字;fd_array是存放套接字的数组; • 有几个相关宏 • FD_ZERO( *set); FD_CLR(s, *set); • FD_ISSET(s, *set); FD_SET(s, *set); • 需要主动把套接字设置为非阻塞模式 • Ioctlsocket();

  11. 异步I/O——Select-2 • int select ( int nfds, //忽略,为了兼容 fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout ); • readfds: 指向套接字集合,检查其中套接字的可读性。相应writefds为检查可写性。最后的exceptfds用于查错。 • Timeout参数设置为0表示无限等待,直到有网络事件发生

  12. 异步I/O——Select-3 • 用法示例 • 假设已经生成了socket sListen; • 声明套接字集合 fd_set fdSoket; • 初始化该集合 FD_ZERO(&fdSoket); • 放入第一个套接字 FD_SET(sListen, &fdSoket) • 声明用于Select函数的套接字集合 • fdRead= fdSoket; • 使用Select函数 • select(0, &fdRead, NULL, NULL, NULL);

  13. 异步I/O——Select-4 • 当select函数返回时,意味着发生了某些网络事件 • 我们传递给select函数不同的套接字集合时,select返回后意味着发生了不同的网络事件 • 如果我们传递了readfds指针,则有新的连接请求、数据可读、连接关闭/重启/中断等事件时返回; • 如果我们传递了writefds指针,则连接成功(调用connect)、数据可写的时候返回; • 如果我们传递了exceptfds指针,则当连接失败(调用connect) 、OOB数据可读时返回;

  14. 异步I/O——Select-5 • 操作步骤 • 初始化套接字集合fdSocket,向该集合添加监听套接字 • 将fdScoket集合的拷贝传递给select函数,当有事件发生时,select函数移除fdRead集合中没有连接事件发生的套接字句柄,返回 • 比较fdSocket与select处理过的fdRead集合,确定哪些套接字有连接,并进一步处理I/O • 返回第2步继续

  15. 异步I/O——Select-6 • Fd_set结构对套接字数量有限制,winsock.h中定义为64;自定义之后不能超过1024 • 因为select需要遍历套接字来决定状态,返回后也需要遍历,所以套接字数量太大性能也会受到影响。

  16. 异步I/O——WSAAsynSelect • Windows 系统专用 • 自动把套接字设置为非阻塞模式 • 为一个套接字绑定到一个窗口句柄 • 先绑定,后listen,之后进入消息循环,处理listen端口上发生的网络事件 • 每一次一个socket上发生某个事件,会触发一次消息发送,执行一次消息处理函数 • 单个Windows函数处理上千用户请求时服务器性能也会受影响

More Related