对于网络IO的理解

网络IO理解

首先服务端将本机地址和端口bind在listensock上,再用listen()去将listensock套接字设置为listen状态,然后调用accept,进入阻塞状态。如果此时有客户端请求连接,就是第一次握手的开始。

客户端会先调用connect来申请连接:

connect调用时是发送SYN,然后服务端返回SYN+ACK,然后客户端的connect返回,发送最后一个ACK,服务端接收到以后accept返回,开始进行read。

在这里插入图片描述

这里的过程,服务端会被阻塞两次,一次是accept,一次是后续的read。

read具体的读取过程就是从sock读取数据到内核缓冲区(网络设备->内核缓冲区),然后read将数据从内核缓冲区拷贝到用户缓冲区(内核缓冲区->用户缓冲区):

在这里插入图片描述

对阻塞IO的理解

这个就是经典的阻塞IO,那么此时就要从read解决问题。

这里要明确一个问题,就绪事件是在数据从网卡拷贝到内核缓冲区以后就产生了,也就是说内核缓冲区有数据了就是就绪事件了。

在这里插入图片描述

对select的理解

如果有多个客户端连接,每个客户端对应一个线程去按部就班处理是不理想的方式。我们可以想到的是把这些fd放在一个容器,然后用一个线程不停地遍历,然后对于有就绪事件的fd进行处理。

对poll的理解

poll相对于select其实就是没有了文件描述符数量的限制,

对epoll的理解

epoll解决了三个问题:

  1. select 调用需要传入 fd 数组,需要拷贝一份到内核,高并发场景下这样的拷贝消耗的资源是惊人的。(可优化为不复制)
  2. select 在内核层仍然是通过遍历的方式检查文件描述符的就绪状态,是个同步过程,只不过无系统调用切换上下文的开销。(内核层可优化为异步事件通知)
  3. select 仅仅返回可读文件描述符的个数,具体哪个可读还是要用户自己遍历。(可优化为只返回给用户就绪的文件描述符,无需用户做无效的遍历)

优化为:

  1. 内核中保存一份文件描述符集合,无需用户每次都重新传入,只需告诉内核修改的部分即可。
  2. 内核不再通过轮询的方式找到就绪的文件描述符,而是通过异步 IO 事件唤醒。
  3. 内核仅会将有 IO 事件的文件描述符返回给用户,用户也无需遍历整个文件描述符集合。

多路复用快的原因在于,操作系统提供了这样的系统调用,使得原来的 while 循环里多次系统调用,变成了一次系统调用 + 内核层遍历这些文件描述符。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值