io

目录

nio

同步、异步、阻塞、非阻塞。
假设一个线程在执行一个io操作,这个io操作需要一定的时候会有数据返回给该线程。
阻塞:如果该线程在等待io返回数据,什么也不做,直到有数据返回,则就是阻塞。
非阻塞如果该线程提交了io操作请求后,去干其他的事情,不等待结果,就是非阻塞。
阻塞非阻塞是指该线程是否卡在这里了。

io操作返回数据如何交给该线程?
同步:如果是该线程不停的询问io是否操作完毕有数据返回,则是同步
异步:如果该线程不去问,而是当io操作完了主动通知该线程有消息了,则是异步
同步异步是指如果获取到回执消息。

bio最基本的同步阻塞,nio基于多路复用实现的同步非阻塞,aio异步非阻塞。

客户端与服务端进行网络通信通常是客户端创建一个socket,服务端创建一个serversocket,然后把这两个socket连接到一起(也就是创建了一个连接),然后服务端开启监听来监听客户端是否有请求过来,如果采用bio的方式,则需要为每一个客户端的连接都创建一个线程(即使没有请求也要创建线程),并发量大的时候服务端需要大量线程,服务端承受不住,nio用来解决这个问题。

io

nio由selector负责对客户端socket进行监听,selector底层是linux的epoll函数实现。

epoll

io

  1. 文件列表fd:代表linux文件系统,用来存储所有涉及的数据
  2. socket队列:数据结构为红黑树,用来存储socket,每个socket代表一个客户端连接,每个socket都持有eventPoll的引用
  3. 工作队列-进程A、B:可以理解成当前运行的进程(线程),CPU挨个执行他们
  4. rdlist:链表结构,用来存储就绪状态的socket(有真正数据过来的socket)
  5. eventPoll:工作进程和socket的中间层,rdlist是它的一个成员,还有一个队列用来存储进程(进程A)
int s = socket(AF_INET, SOCK_STREAM, 0);    
bind(s, ...) 
listen(s, ...) 
 
int epfd = epoll_create(...); 
epoll_ctl(epfd, ...); //将所有需要监听的socket添加到epfd中 
 
while(1){ 
    int n = epoll_wait(...) 
    for(接收到数据的socket){ 
        //处理 
    } 
} 
  1. 执行epoll_create函数:cpu创建eventpoll对象
  2. 调用epoll_ctl函数:cpu添加socket到文件系统,同时将eventpoll设置到socket中
  3. 执行epoll_wait:将进程A添加到eventpoll的队列并且阻塞。
  4. 当socket有真正数据过来的时候,cpu通过该socket的eventpoll引用,将socket添加到eventpoll的rdlist中。同时cpu会唤醒进程A,进程A就会查询rdlist,在rdlist中发现有就绪的socket,直接带着socket进入工作队列等待cpu调用执行

返回顶部

上一篇:Linux高并发学习----一请求一线程/select/poll/epoll基本使用


下一篇:2020-11-29 epoll函数的基本使用过程