IO
2025-09-18 17:15:00 0 举报
AI智能生成
IO
作者其他创作
大纲/内容
socket
定义
起源于Unix,而Unix/Linux基本思想之一就是“一切皆文件”,也称为文件描述符
Socket是对“open—write/read—close”模式的一种实现
Socket是对TCP/IP协议的封装,Socket本身不是协议,通过Socket才能使用TCP/IP协议
连接四要素
源IP
目标IP
源端口
目标端口
底层数据结构
同步/异步
所谓同步/异步,描述的被调用者,关注的是能不能同时开工
譬如A调用B。
如果是同步,B在接到A的调用后,会立即执行要做的事。A的本次调用可以得到结果。
如果是异步,B在接到A的调用后,不保证会立即执行要做的事,但是保证会去做,B在做好了之后会通知A。A的本次调用得不到结果,但是B执行完之后会通知A。
如果是同步,B在接到A的调用后,会立即执行要做的事。A的本次调用可以得到结果。
如果是异步,B在接到A的调用后,不保证会立即执行要做的事,但是保证会去做,B在做好了之后会通知A。A的本次调用得不到结果,但是B执行完之后会通知A。
阻塞/非阻塞
所谓阻塞/非阻塞,描述的是调用者,关注的是能不能动。
A调用B。
如果是阻塞,A在发出调用后,要一直等待,等着B返回结果。
如果是非阻塞,A在发出调用后,不需要等待,可以去做自己的事情。
同步不一定阻塞,异步也不一定非阻塞。没有必然关系。
如果是阻塞,A在发出调用后,要一直等待,等着B返回结果。
如果是非阻塞,A在发出调用后,不需要等待,可以去做自己的事情。
同步不一定阻塞,异步也不一定非阻塞。没有必然关系。
BIO:同步阻塞IO
一个请求一个线程,线程发起IO请求后,一直阻塞,直到数据被读取或写入完毕。
从系统调用recv到将数据从内核复制到用户空间并返回,在这段时间内进程始终阻塞。
从系统调用recv到将数据从内核复制到用户空间并返回,在这段时间内进程始终阻塞。
适用场景:适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
socket交互整体流程
NIO:同步非阻塞IO
一个线程处理多个请求(连接),线程发起IO请求后,不需要阻塞,立即返回。发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有 I/O 请求就进行处理。并且引入了通道(Channel)和缓冲区(Buffer)的概念。
在这里recv不管有没有获得到数据都返回,如果没有数据的话就过段时间再调用recv看看,如此循环
在这里recv不管有没有获得到数据都返回,如果没有数据的话就过段时间再调用recv看看,如此循环
适用场景:适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
三要素
channel: 介于字节缓冲区和套接字之间,可以同时读写,支持异步IO
buffer: 字节缓冲区,是应用程序和通道之间进行IO数据传输的中转
selector:多路复用器,监听服务端和客户端的管道上注册的事件
AIO:异步非阻塞I/O
线程发起IO请求后,不需要阻塞,立即返回,也不需要定时轮询检查结果,异步IO操作之后会回调通知调用方。
调用aio_read令内核把数据准备好,并且复制到用户进程空间后执行事先指定好的函数。
调用aio_read令内核把数据准备好,并且复制到用户进程空间后执行事先指定好的函数。
适用场景:适用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
多路复用IO
在IO复用模型中,调用recv之前会先调用select或poll,这两个系统调用都可以在内核准备好数据(网络数据已经到达内核了)时告知用户进程,它准备好了,这时候再调用recv时是一定有数据的。因此在这一模型中,进程阻塞于select或poll,而没有阻塞在recv上。
select/poll
epoll
如何理解select、poll、epoll
select, poll, 和 epoll 都是 Linux 中常见的 I/O 多路复用技术,它们可以用于同时监听多个文件描述符(file descriptor,后文简称fd),当任意一个文件描述符就绪时,就能够非阻塞的读写数据。
select
是最原始的 I/O 多路复用技术,select函数可以监听read,write,except的fd。当select返回后,可以遍历对应的fd_set来寻找就绪的fd,从而进行业务处理。缺点是最多只能监听 1024 个文件描述符,并且大量fd的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,其开销也随着文件描述符数量增加而线性增大。
poll
同select一样,poll返回后,也是需要轮询pollfd来获取就绪的fd。不仅如此,所有的fds也是在内核态和用户态中来回切换,也会影响效率。
但是因为fds基于链表,所以就没有了最长1024的限制。但是复杂度随着监听的文件描述符数量的增加而增加。
但是因为fds基于链表,所以就没有了最长1024的限制。但是复杂度随着监听的文件描述符数量的增加而增加。
epoll
每次注册新的事件调用epoll_ctl(注册监听事件类型命令)时,epoll会把所有的fd拷贝进内核,而不是在epoll_wait(等待事件发生)的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次。
同时,epoll会通过epoll_wait查看是否有就绪的fd,如果有就绪的fd,就会直接使用(O(1))。而不是像之前两个一样,每次需要手动遍历才能得到就绪的fd(O(n))
除此之外,它所支持的fd上限是最大可以打开文件的数目,这个数字一般远大于2048,
同时,epoll会通过epoll_wait查看是否有就绪的fd,如果有就绪的fd,就会直接使用(O(1))。而不是像之前两个一样,每次需要手动遍历才能得到就绪的fd(O(n))
除此之外,它所支持的fd上限是最大可以打开文件的数目,这个数字一般远大于2048,
LT(level trigger)
LT模式:当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用epoll_wait时,会再次响应应用程序并通知此事件
ET(edge trigger)
ET模式:当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次响应应用程序并通知此事件。
因为ET模式在很大程度上减少了epoll事件被重复触发的次数,因此效率要比LT模式高。epoll工作在ET模式的时候,必须使用非阻塞socket,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。
信号驱动IO
此处会通过调用sigaction注册信号函数,在内核数据准备好的时候系统就中断当前程序,执行信号函数(在这里调用recv)。
0 条评论
下一页