三次握手:面向连接的可靠的网络协议
socket:客户端向 服务端发起请求 seq, 服务端收到请求后 向服务端返回 seq + ack ,客户端收到服务端发回的请求后 向服务端发送 ack。自此三次握手完成,此后双方会开辟资源
IO层面的同步、异步、阻塞、非阻塞一个四元组包含了 ClientIP + Cport + SserverIP + Sport 开辟资源后 会加上文件描述符
同步:read/write操作需要 application 进行操作
异步:read/write操作不需要application进行操作
组合: 同步阻塞(BIO) 、同步非阻塞(NIO)、异步非阻塞(AIO)
下面我们只讨论BIO/NIO
网络IO模型 BIO:同步阻塞NIO:同步非阻塞accept / read 都会阻塞,此时主线程会抛出大量的线程。影响效率
NIO :accept/read时不会阻塞。可以通过一个或n个线程解决开辟线程的问题
1.但是每循环1次 都需要遍历请求的socket是否就绪,时间复杂度为O(n)。有很多的调用是无效的调用
2.每次遍历都需要用户态内核态的切换,影响性能
如何解决上述问题
多路复用器:Select/Poll多路复用的理解
多路:多个文件描述符
复用:公用一个接口,用户只需要有限次的用户态内核态的切换,就能取到已经准备好的资源
epollselect 和 poll的方式类似,最大的区别 select收到最大文件描述符数量影响。poll不受影响
用户态将需要查询的文件描述符 fds 传给 select/poll 由select/poll 进行状态查询,并返回已经准备好的文件描述符
app 根据结果fds 进行对应的操作
扩展:基于消息通知的多路复用
针对select/poll 我们可以发现每次都要重新传递fds,每次被调用后针对这次调用,触发遍历全量的复杂度。也有很多没必要的查询
其实在内核中,如果fds状态改变,内核是能感知到的。如果在感知到的同时,将fds存储下来,下次app查询时,直接将准备好的数据传回去,这样会大大的提高效率。
主要的三个函数:
epoll_create: 函数生成一个epoll专用的文件描述符。它其实是在内核申请一空间,用来存放你想关注的socket fd上是否发生以及发生了什么事件
epoll_ctl:fds集合 并且会以红黑树的形式存储。
epoll_wait:当某个文件描述符事件触发,会将该事件复制到内存中的一个链表中,等下次函数被app调用时,直接返回即可
Redis底层网络模型正是使用了epoll的方式,这也是redis为什么快的原因之一。



