记一次网络io学习流水账

一次网络io学习流水账

buffer & NIO & BIO

最近在学习redis线程io模型时,遇到内核缓冲区的概念,然后我由这个名称联想到学习计网时也出现过的读写Buffer,资料一查,这两个就是同一个东西。

这个buffer是处于网络的应用层和运输层之间,当应用程序调用操作系统的 write() 函数时,数据就会先被存放在这个Send buffer中,接下来TCP就会不时从发送缓存里取出一块数据,并将数据传递到网络层。同理,当应用程序调用操作系统的 read() 函数时,就是从缓存里读数据。

我们知道,redis服务器是非阻塞读,也就是如果receive buffer中,如果没有数据,会直接返回,而不会被阻塞。非阻塞模式还是阻塞模式是由套接字(Socket)的属性决定的 ,而这个属性是由应用程序在创建或配置套接字时主动设置的。

然后又让我联系到NIO和BIO。NIO就是非阻塞读,BIO就是阻塞读。在我的知识库里还浅显的知道netty是Java NIO框架。

  • 一个网络连接 在程序中体现为一个 Socket 对象。

  • 在BIO模式下 :一个线程在执行这些IO操作时,如果条件不满足(如无数据可读),线程会被挂起,这个线程也就被这个Socket独占,无法去处理其他Socket。因此是 "一个线程一个连接"

  • 在NIO模式下 :通过Selector(选择器) ,一个线程可以轮询无数个Socket,只去处理那些已经"就绪"(有数据可读、可以写入数据等)的Socket上的IO操作。因为操作不会阻塞,线程可以快速地在所有就绪的连接之间切换。因此是 "一个线程多个连接"

接着,我又提出疑惑,用户在浏览器发送HTTP请求到服务端与TCP的关系?

答案是:HTTP协议是建立在TCP协议之上的。浏览器发送HTTP请求之前,必须先在网络上建立一条可靠的TCP连接作为"通道"。

当TCP三次握手成功建立好连接后,浏览器通过调用操作系统的 write() 或 send() 函数,将这个HTTP报文写入到本地的TCP Send Buffer(发送缓冲区) 中。操作系统的TCP/IP协议栈会负责将Send Buffer里的数据(即你的HTTP请求)分割成多个TCP段(Segment),通过之前建立的TCP连接这个"通道", 可靠地发送给服务器。服务器的Web服务器程序(如Nginx、Tomcat)调用 read() 从Receive Buffer中读取到的就是一整个完整的HTTP请求报文

当Receive Buffer中有数据时,我们继续分析Java服务器(如Tomcat的NIO连接器、Netty)是怎么NIO的:

HTTP/1.0 (短连接模式) vs HTTP/1.1 Keep-Alive (持久连接) vs WebSocket

  • 没有Keep-Alive时一个TCP连接 只用于传输 一对 HTTP请求/响应
  • 有Keep-Alive时一个TCP连接 可以用于传输 多对 HTTP请求/响应。只有当这条连接空闲时间超过超时时间,才会被关闭。

HTTP/1.1 Keep-Alive (持久连接) vs WebSocket

HTTP/1.1 Keep-Alive 和 WebSocket 都复用了底层的TCP连接,但是二者区别如下:

特性 HTTP/1.1 Keep-Alive WebSocket
通信模式 半双工(Half-Duplex) :请求-响应循环。必须客户端先发起,服务器才能响应。严格的一问一答 全双工(Full-Duplex) :客户端和服务器完全平等,任何一方都可以在任何时候主动向对方发送数据。
服务器主动性 完全被动:服务器永远不能主动推送消息给客户端。客户端必须不断"轮询"询问。 完全主动:服务器可以随时主动向客户端推送消息。
协议开销 每个HTTP请求和响应都必须携带完整的、冗长的头部(如cookie、user-agent等),即使大部分是重复的。 极小 :只在初始握手时有HTTP头。之后的数据传输使用轻量级的数据帧,头部长仅2-10字节。
设计目的 优化传统Web浏览的体验:减少重复建立TCP连接的开销,让一个页面中的多个资源(图片、CSS、JS)能更快加载。 实现实时双向Web应用:为在线聊天、实时游戏、股票行情、协同编辑等场景提供底层支持。

一个网页聊天室的实现可以很好的看出这两者的区别:

  • 使用 HTTP/1.1 Keep-Alive
    1. 你的浏览器(客户端)必须每隔一秒就向服务器发送一个请求 :"有新消息吗?"(这叫轮询 Polling)。
    2. 服务器回答:"没有。" 或 "有,这里是消息。"
    3. 这个过程会产生大量无用的请求(问"有新消息吗?"),并且消息到达有延迟(最多要等1秒)。效率极低。
  • 使用 WebSocket
    1. 建立WebSocket连接。
    2. 然后,双方就保持沉默,直到有人说话
    3. 你发送一条消息,服务器瞬间收到。
      cket连接。
    4. 然后,双方就保持沉默,直到有人说话
    5. 你发送一条消息,服务器瞬间收到。
    6. 另一个用户发送了一条消息,服务器立刻、主动地将这条消息推送到你的浏览器上,完全不需要你询问。
相关推荐
is08154 小时前
全志 H3 armbian 备份
linux·服务器·网络
初圣魔门首席弟子4 小时前
C++ STL string(字符串)学习笔记
c++·笔记·学习
LGL6030A4 小时前
数据结构学习(2)——多功能链表的实现(C语言)
数据结构·学习·链表
iconball4 小时前
个人用云计算学习笔记 --18(NFS 服务器、iSCSI 服务器)
linux·运维·笔记·学习·云计算
国科安芯5 小时前
ASP4644芯片低功耗设计思路解析
网络·单片机·嵌入式硬件·安全
艾菜籽5 小时前
网络原理-HTTPS
网络·网络协议·https
肥肠可耐的西西公主5 小时前
后端(JavaWeb)学习笔记(CLASS 1):maven
笔记·学习·maven
努力学习的小廉5 小时前
深入了解linux网络—— TCP网络通信(下)
linux·网络·tcp/ip
Bruce_Liuxiaowei8 小时前
MQTT协议在物联网环境中的安全风险与防范指南
运维·网络·物联网·安全·网络安全