前言:本篇没有介绍最好的IO模型 epoll(非阻塞异步),是性能最好的。但是本篇不做介绍。

http://www.ibm.com/developerworks/cn/linux/l-async/

http://blog.csdn.net/piggyxp/article/details/6922277

http://daojin.iteye.com/admin/blogs/1300709

连接中的那篇socket拉屎模型严重脱离实际,有人可能觉得这感觉不实在,或者说,没有接触实际。本篇文章就对上述进行补充,请看如下时序图:

关键概念:

1.同步意思是发送一个Read/Write(读和写,是一种抽象概念)命令来获得数据,如果发了两个命令 如 select和read/write 才能把数据弄到数,那么就叫做异步。

2.阻塞的意思是 一个Read/write函数,如果没有数据,就不返回。叫做阻塞,是一种局部概念。

1.同步阻塞模型。

我们注意到,大部分的 socket 接口都是阻塞型的。所谓阻塞型接口是指系统调用(一般是 IO 接口)不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回。

实际上,除非特别指定,几乎所有的 IO 接口 ( 包括 socket 接口 ) 都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用 send() 的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。这给多客户机、多业务逻辑的网络编程带来了挑战。这时,很多程序员可能会选择多线程的方式来解决这个问题。

2.多线程的服务器程序(同步阻塞模型之二)

多线程的服务器程序

应对多客户机的网络应用,最简单的解决方式是在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接。

具体使用多进程还是多线程,并没有一个特定的模式。传统意义上,进程的开销要远远大于线程,所以,如果需要同时为较多的客户机提供服务,则不推荐使用多进程;如果单个服务执行体需要消耗较多的 CPU 资源,譬如需要进行大规模或长时间的数据运算或文件访问,则进程较为安全。通常,使用 pthread_create () 创建新线程,fork() 创建新进程。

我们假设对上述的服务器 / 客户机模型,提出更高的要求,即让服务器同时为多个客户机提供一问一答的服务。于是有了如下的模型。

在上述的线程 / 时间图例中,主线程持续等待客户端的连接请求,如果有连接,则创建新线程,并在新线程中提供为前例同样的问答服务。

很多初学者可能不明白为何一个 socket 可以 accept 多次。实际上,socket 的设计者可能特意为多客户机的情况留下了伏笔,让 accept() 能够返回一个新的 socket。下面是 accept 接口的原型:

     int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

输入参数 s 是从 socket(),bind() 和 listen() 中沿用下来的 socket 句柄值。执行完 bind() 和 listen() 后,操作系统已经开始在指定的端口处监听所有的连接请求,如果有请求,则将该连接请求加入请求队列。调用 accept() 接口正是从 socket s 的请求队列抽取第一个连接信息,创建一个与 s 同类的新的 socket 返回句柄。新的 socket 句柄即是后续 read() 和 recv() 的输入参数。如果请求队列当前没有请求,则 accept() 将进入阻塞状态直到有请求进入队列。

上述多线程的服务器模型似乎完美的解决了为多个客户机提供问答服务的要求,但其实并不尽然。如果要同时响应成百上千路的连接请求,则无论多线程还是多进程都会严重占据系统资源,降低系统对外界响应效率,而线程与进程本身也更容易进入假死状态。

很多程序员可能会考虑使用“线程池”或“连接池”。“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的线程,并让空闲的线程重新承担新的执行任务。“连接池”维持连接的缓存池,尽量重用已有的连接、减少创建和关闭连接的频率。这两种技术都可以很好的降低系统开销,都被广泛应用很多大型系统,如 websphere、tomcat 和各种数据库等。

但是,“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用 IO 接口带来的资源占用。而且,所谓“池”始终有其上限,当请求大大超过上限时,“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模,并根据响应规模调整“池”的大小。

对应上例中的所面临的可能同时出现的上千甚至上万次的客户端请求,“线程池”或“连接池”或许可以缓解部分压力,但是不能解决所有问题。

总之,多线程模型可以方便高效的解决小规模的服务请求,但面对大规模的服务请求,多线程模型并不是最佳方案。下一章我们将讨论用非阻塞接口来尝试解决这个问题。

3.非阻塞同步IO(一个不好的例子)

在非阻塞状态下,recv() 接口在被调用后立即返回,返回值代表了不同的含义。如在本例中,

  • recv() 返回值大于 0,表示接受数据完毕,返回值即是接受到的字节数;
  • recv() 返回 0,表示连接已经正常断开;
  • recv() 返回 -1,且 errno 等于 EAGAIN,表示 recv 操作还没执行完成;
  • recv() 返回 -1,且 errno 不等于 EAGAIN,表示 recv 操作遇到系统错误 errno。

可以看到服务器线程可以通过循环调用 recv() 接口,可以在单个线程内实现对所有连接的数据接收工作。

但是上述模型绝不被推荐。因为,循环调用 recv() 将大幅度推高 CPU 占用率;此外,在这个方案中,recv() 更多的是起到检测“操作是否完成”的作用,实际操作系统提供了更为高效的检测“操作是否完成“作用的接口,例如 select()。


4.改善轮询(异步阻塞IO)select 和poll

使用 select() 接口的基于事件驱动的服务器模型

大部分 Unix/Linux 都支持 select 函数,该函数用于探测多个文件句柄的状态变化。下面给出 select 接口的原型:

 FD_ZERO(int fd, fd_set* fds)
FD_SET(int fd, fd_set* fds)
FD_ISSET(int fd, fd_set* fds)
FD_CLR(int fd, fd_set* fds)
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout)

这里,fd_set 类型可以简单的理解为按 bit 位标记句柄的队列,例如要在某 fd_set 中标记一个值为 16 的句柄,则该 fd_set 的第 16 个 bit 位被标记为 1。具体的置位、验证可使用 FD_SET、FD_ISSET 等宏实现。在 select() 函数中,readfds、writefds 和 exceptfds 同时作为输入参数和输出参数。如果输入的 readfds 标记了 16 号句柄,则 select() 将检测 16 号句柄是否可读。在 select() 返回后,可以通过检查 readfds 有否标记 16 号句柄,来判断该“可读”事件是否发生。另外,用户可以设置 timeout 时间。

下面将重新模拟上例中从多个客户端接收数据的模型。

上述模型只是描述了使用 select() 接口同时从多个客户端接收数据的过程;由于 select() 接口可以同时对多个句柄进行读状态、写状态和错误状态的探测,所以可以很容易构建为多个客户端提供独立问答服务的服务器系统。

  • 大小: 16.1 KB
  • 大小: 32.4 KB
  • 大小: 23.7 KB
  • 大小: 26 KB
  • 查看图片附件

Socket拉屎模型之二--实践篇相关推荐

  1. Socket拉屎模型之epoll

    参考如下蚊帐,也就是传说中的异步非阻塞: e poll e的含义是event---------事件探测. poll 则是探测的意思. 这里的阻塞主要是说epoll的调用,传入一个结构体用于记录事件,并 ...

  2. 很幽默的讲解六种Socket IO模型

    很幽默的讲解六种Socket IO模型   本文简单介绍了当前Windows支持的各种Socket I/O模型,如果你发现其中存在什么错误请务必赐教. 一:select模型 二:WSAAsyncSel ...

  3. 很幽默的讲解六种Socket IO模型(转)

    本文简单介绍了当前Windows支持的各种Socket I/O模型,如果你发现其中存在什么错误请务必赐教. 一:select模型 二:WSAAsyncSelect模型 三:WSAEventSelect ...

  4. 潜在狄利克雷分配(LDA,Latent Dirichlet Allocation)模型(二)

    潜在狄利克雷分配(LDA,Latent Dirichlet Allocation)模型(二) 目录 潜在狄利克雷分配(LDA,Latent Dirichlet Allocation)模型(二) LDA ...

  5. django模型——数据库(二)

    模型--数据库(二) 实验简介 模型的一些基本操作,save方法用于把对象写入到数据库,objects是模型的管理器,可以使用它的delete.filter.all.order_by和update等函 ...

  6. Socket通信学习(二):序列化与反序列化

    Socket通信学习(二):序列化与反序列化 HoloLens的开发最近需要用到Socket通信,所以创建本系列进行记录,欢迎大家批评指正! 前言 Socket通信的默认发送的数据为byte[]类型, ...

  7. 评分卡模型(二)基于评分卡模型的用户付费预测

    评分卡模型(二)基于评分卡模型的用户付费预测 小P:小H,这个评分卡是个好东西啊,那我这想要预测付费用户,能用它吗 小H:尽管用- (本想继续薅流失预测的,但想了想这样显得我的业务太单调了,所以就改成 ...

  8. 时间序列模型 (二):移动平均法

    时间序列的其它博文系列: 时间序列模型 (一):模型概述 时间序列模型 (二):移动平均法 时间序列模型 (三):指数平滑法 时间序列模型 (四):差分指数平滑法. 自适应滤波法v 时间序列模型 (五 ...

  9. 8. Django 模型(二)

    Django 模型(二) 版权声明:本博客来自路飞学城Python全栈开发培训课件,仅用于学习之用,严禁用于商业用途. 欢迎访问路飞学城官网:https://www.luffycity.com/ 本节 ...

最新文章

  1. python【力扣LeetCode算法题库】914. 卡牌分组(reduce collections.Counter)
  2. Python函数01/函数的初识/函数的定义/函数调用/函数的返回值/函数的参数
  3. 『骑士精神 IDA*』
  4. 计算机错误英语,计算机启动提示:引导时解释英语错误消息的含义
  5. Python暴力破解附近局域网WiFi密码
  6. 黑苹果系统镜像稳定版 10.9.5 - 10.15.6 整合下载
  7. de4dot命令 v2.0.3.3405 破解命令
  8. python正版软件多少钱_多款正版软件 + 付费教程迎来史低价,少数派「双十一」活动全面开始...
  9. PDF书签制作的方法!
  10. 实战项目一、安居客(北京) 二手房抓取房源信息
  11. 夜晚,我路过那座城市
  12. 一个女大学生骂她男朋友的话,厉害,没一个脏字
  13. 小红书引流软件有哪些
  14. mysql的mtr是指什么_关于innodb mtr模块
  15. 接口测试自动化的思考与总结
  16. Git fatal unable to auto-detect email address
  17. vue el-input绑定enter按键
  18. WIN10+VS2015+PCL1.8.1的配置
  19. 《三体》动画热播,当代人类能用量子计算突破智子封锁吗?
  20. 4.M2Eclipse插件的安装使用

热门文章

  1. 织梦 m list.php tid,在织梦标签dede:list中增加noflag属性的方法支持5.7版本
  2. c语言小程序跑马灯,微信小程序实现跑马灯效果(完整代码)
  3. python递归合并排序_python 归并排序的递归法与迭代法(利用队列)实现,以及性能测试...
  4. 人生苦短,我用python+vscode
  5. 获取图像的梯度,方向和方向梯度图像
  6. 财务python招聘_会计、财务、HR等重复性质岗位学习python有什么帮助?
  7. 华为云AIOps实践全面解析
  8. 小程序首页获取数据给数组赋值,实现加载更多,以及遇到的坑
  9. 两队选手每队5人进行一对一的比赛(算法)
  10. 系统管理员在企业中的职业定位及发展方向 连载(二)