记一次网络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. 另一个用户发送了一条消息,服务器立刻、主动地将这条消息推送到你的浏览器上,完全不需要你询问。
相关推荐
Harm灬小海6 分钟前
【云计算学习之路】学习Centos7系统-Linux软件包管理
linux·运维·服务器·学习·云计算·yum·rpm
pengyi8710157 分钟前
共享 IP 防封维护策略,降低被封率、延长 IP 寿命
网络·网络协议·tcp/ip
魔法阵维护师14 分钟前
从零开发游戏需要学习的c#模块,第十七章(显示真正的图片——精灵绘制)
学习·游戏
婷婷_17214 分钟前
JTAG (IEEE 1149.1)学习记录
学习·程序人生·debug·芯片·jtag·phy·eth/pcie
ygkl969820 分钟前
未完待续 模拟题
学习
几司32 分钟前
OpenISP 模块拆解 · 第1讲:坏点校正 (DPC)
笔记·学习·isp
制造业的搬运工33 分钟前
高端电路板哪家好:专业视角下的选择逻辑
网络·pcb工艺·pcb
Yeats_Liao35 分钟前
物联网接入层技术剖析(二):epoll到底是怎么工作的
java·linux·网络·物联网·信息与通信
-To be number.wan39 分钟前
计算机组成原理 | 定点数加减运算
学习·计算机组成原理
吃好睡好便好40 分钟前
在Matlab中绘制杆状图
开发语言·学习·算法·matlab·信息可视化