I/O多路复用和Socket
由于IO操作涉及到系统调用,涉及到用户空间和内核空间的切换,所以理解系统的IO模型,对于需要进入到系统调用层面进行编程来说是很重要的。
阻塞IO和非阻塞IO
从程序编写的角度来看,I/O就是调用一个或多个系统函数,完成对输入输出设备的操作。输入输出设置可以是显示器、字符终端命令行、网络适配器、磁盘等。操作系统在这些设备与用户程序之间完成一个衔接,称为驱动程序,驱动程序向下驱动硬件,向上提供抽象的函数调用入口。
一般来说I/O操作是需要时间的,因为这涉及到系统、硬件等计算器模块的互相配合,所以必然不像普通的函数调用那样能够按照既定的方式立即返回。从用户代码的角度,I/O操作的系统调用分为“阻塞”和“非阻塞”两种。
- “阻塞”的调用会在I/O调用完成前,挂起调用线程,即CPU会不再执行后续代码,而是等到I/O完成后再回来继续执行,在用户代码看来,线程停止执行了,在调用处等待了。
- “非阻塞”的调用则不同,I/O调用基本上是立即返回,而且往往实际上I/O此时并没有完成,所以需要用户的程序轮询结果。
那么我们以网络IO为例,看一下对于一个服务器,“阻塞”和“非阻塞”两种模式,该如何设计。由于服务器要同时服务多个客户端,所以需要同时操作多个Socket。
可以看到,如果使用阻塞的IO方式,因为每个Socket都会阻塞,为了同时服务多个客户端,需要多个线程同时挂起;而如果采用非阻塞的调用方式,则需要在一个线程中不断轮训每个客户端是否有数据到来。
显然纯粹阻塞式的调用不可取,非阻塞式的调用看起来不错,但是仍不够好,因为轮询实际也是通过某种系统调用完成的,相当于在用户空间进行的,效率不高,如果能够在内核空间进行这种类似轮询,然后让内核通知用户空间哪个IO就绪了,就更好了。于是引出接下来的概念:IO多路复用
IO多路复用
IO多路复用是一种系统调用,内核能够同时对多个IO描述符进行就绪检查。当所有被监听的IO都没有就绪时,调用将阻塞;当至少有一个IO描述符就绪时,调用将返回,用户代码可通过检查究竟是哪个IO就绪来进一步处理业务。显然,IO多路复用是解决系统里面存在N个IO描述符的问题的,这里必须明确IO复用和IO阻塞与否并不是一个概念,IO复用只检测IO是否就绪(读就绪或者写就绪等),具体的数据的输入输出还是需要依靠具体的IO操作完成(阻塞操作或非阻塞操作)。最典型的IO多路复用技术有select
、poll
、epoll
等。select
具有最大数量描述符限制,而epoll
则没有,并且在机制上,epoll
也更为高效。select
的优势仅仅是跨平台支持性,所有平台和较低版本的内核都支持select
模式,epoll
则不是。
在IO相关的编程中,IO复用起到的作用相当于一个阀门,让后续IO操作更为精准高效。
编程模型
综上讨论,我们在进行实际的Socket编程的时候,无论是客户端还是服务端,大致有几种模式可以选择:
- 阻塞式。纯采用阻塞式,这种方式很少见,基本只会出现在demo中。多个描述符需要用多个进程或者线程来一一对应处理。
- 非阻塞式。纯非阻塞式,对IO的就绪与否需要在用户空间通过轮询来实现。
- IO多路复用+阻塞式。仅使用一个线程就可以实现对多个描述符的状态管理,但由于IO输入输出调用本身是阻塞的,可能出现某个IO输入输出过慢,影响其他描述符的效率,从而体现出整体性能不高。此种方式编程难度比较低。
- IO多路复用+非阻塞式。在多路复用的基础上,IO采用非阻塞式,可以大大降低单个描述符的IO速度对其他IO的影响,不过此种方式编程难度较高,主要表现在需要考虑一些慢速读写时的边界情况,比如读黏包、写缓冲不够等。
下面以select为例,整理 在select下,socket的阻塞和非阻塞的一些问题。这些细节在编写基于Socket的网络程序时,尤其是底层数据收发时,是十分重要的。
socket读就绪:
- 【阻/非阻】接收缓冲区有数据,数据量大于
SO_RCVLOWAT
水位(默认是0)。此时调用recv
将返回>0(即读到的字节数)。 - 【阻/非阻】对端关闭,即收到FIN。此时调用
recv
将返回=0。 - 【阻/非阻】
accept
到一个新的连接,此时accept通常不会阻塞。 - 【阻/非阻】socket发生某种错误。此时调用recv将返回-1,并应通过
getsockopt
得到相应的待处理错误。
socket写就绪:
- 【阻/非阻】发送缓冲区有空余的空间,空间大小大于
SO_SNDLOWAT
水位(默认是2048)。这种就绪是水平触发的,只要有空间就会触发写就绪,即如果保持对这种套接字的就绪检查将使得select
每次都认为有描述符写就绪。所以应当对描述符进行写状态管理,一旦某个描述符可写,应立即停止对该描述符的写状态检查,直到写缓冲区满后,再次select写状态。 - 【阻/非阻】连接的写半部关闭,此时调用send将产生
SIGPIPE
信号。 - 【非阻】
connect
完成。由于非阻的connect将不会阻塞握手过程,所以,当握手在后续时刻完成后,在此保持写状态检查,将触发一次就绪,表示connect完成。 - 【阻/非阻】socket发生某种错误。此时调用
send
将返回-1,并应通过getsockopt
得到相应的待处理错误。
补充:
非阻的调用recv
、send
、accept
,分别地,如果收缓冲中无数据、发送缓冲不够空间发、没有外来连接,将立即返回,此时全局errno
将得到EWOULDBLOCK
或EAGIAN
,表示“本应阻塞的调用,由于采用了非阻塞模式,而返回”。非阻的调用connect
将立即返回,此时全局errno
将得到EINPROGRESS
,表示连接正在进行。
转自:http://www.pchou.info/c-cpp/2016/02/29/socket-io.html
https://segmentfault.com/a/1190000004537204
I/O多路复用和Socket的更多相关文章
- python基础-11 socket,IO多路复用,select伪造多线程,select读写分离。socketserver源码分析
Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...
- Python之路【第七篇续】:I/O多路复用
回顾原生Socket 一.Socket起源: socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用[打开][读写][关闭]模式来操作. socket就是该模式的 ...
- Python Socket请求网站获取数据
Python Socket请求网站获取数据 ---阻塞 I/O ->收快递,快递如果不到,就干不了其他的活 ---非阻塞I/0 ->收快递,不断的去问,有没有送到,有没有送到,. ...
- Python网络编程(http协议,IO多路复用、select内核监听)
前言: 什么是IO? 分为IO设备和IO接口两个部分 如Linux系统,I/O操作可以有多种方式 比如DIO(DirectI/O) AIO(AsynchronousI/O异步I/O) Memory-M ...
- 第二十三篇、IO多路复用 二
基于IO多路复用实现socket的连接 下面流程:1.先创建列表,让自己的socket对象传入,然后遍历select第一个参数2.客户端连接,那么客户端socket就传入到了列表里面,3.遍历,接收客 ...
- 实现socket并发的几种方法
# 使用多进程实现socket聊天并发-server #服务端 import socket from multiprocessing import Process def server(conn,ad ...
- python之socket编程(二)
标签(空格分隔): socket编程 SocketServer解析 SocketServer内部使用I/O多路复用,多线程,多进程来实现客户端多并发访问Socket服务端,while循环时使用I/O多 ...
- Python全栈开发:socket代码实例
客户端与服务端交互的基本流程 服务端server #!/usr/bin/env python # -*- coding;utf-8 -*- import socket sk = socket.sock ...
- 【python之路35】网络编程之socket相关
Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...
随机推荐
- [javase学习笔记]-8.6 静态的内存载入
之前几节我们一直在说statickeyword所修饰的静态,那么在程序执行时,内存中static是怎样体现的呢?这一节我们就来看一看. 我们还是先看一个样例.希望我们通过对这个样例的分析让我们刚開始学 ...
- shell - 常识
一.用户登陆进入系统后的系统环境变量: $HOME 使用者自己的目录 $PATH 执行命令时所搜寻的目录 $TZ 时区 $MAILCHECK 每隔多少秒检查是否有新的信件 $PS1 在命令列时的提示号 ...
- 怎么设置Linux swap分区?方法教程
如何设置Linux swap分区 看到不少朋友问linux下swap分区的问题,收集到一篇 不错的文章 ,分享下. 什么是Swap?Swap,即交换区,除了安装Linux的时候,有多少人关心过它呢?其 ...
- Atitti 过程导向 vs 结果导向 attilax的策略
Atitit 世界著名零食 1.1. /////milk hand candy , milk soft candy . fruit soft candy1 1.2. ==========cookie ...
- Java常考面试题(一)
序言 我是一只乱飞乱撞的菜鸟,写的文章目前是以记录自己学习,和方便以后查看,期待日后不久能通过自己的努力,获得一点小小的成功,然后写出我的学习经验总结性文章来. ---WH 一.什么是虚拟机?为什么J ...
- [sql]mysql指引(整理中...)-对db的分类
参考 db存储及分层 一个db一个文件夹. 一张表两个文件frm是存表结构的,ibd是存数据的 连接层: sock ip sql层: 存储层: 2018年4月1日 20:53:54小结: 时间太久,抓 ...
- crontab -e 新法
SHELL=/bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root 0 3 * * * /home/rsync.sh //每天晚上3点执行一次同步 ...
- u3d中的INput
属性 属性: 功能: 轴 (Axes) 包含当前工程的所有定义的输入轴:数目 (Size) 该工程中不同输入轴的数量,元素 0.1.... 是要修改的特定的轴. 名称 (Name) 在游戏启动器中以及 ...
- HBase 管理,性能调优
设置 Hadoop 来扩展磁盘 I/O 现代服务器通常有多个磁盘硬件来提供大存储能力.这些磁盘通常配置成 RAID 阵列,作为它们的出厂设置.这在很多情况下是有益的,但对 Hadoop 却不是. Ha ...
- 【C/C++】exit不兼容解决方案
1.问题 今天在编译一个基于原始套接字实现网络数据包嗅探程序时出现了如下错误: 警告: 隐式声明与内建函数 ‘exit’ 不兼容 2.解决方案 后面发现没有把stdlib.h包 ...