从浏览器输入网址到网页显示内容——协议栈

本文深入解析了网络通信的基础原理,包括套接字的概念、TCP/IP协议的工作机制、数据包的发送与接收流程,以及UDP协议的特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建套接字

协议栈内部结构

在这里插入图片描述几点说明

  • 像浏览器、 邮件等一般的应用程序都是使用 TCP 收发数据的, 而像 DNS 查询等收发较短的控制数据的时候则使用 UDP。
  • 在互联网上传送数据时, 数据会被切分成一个一个的网络包 A, 而将网络包发送给通信对象的操作就是由 IP 来负责的。 此外, IP 中还包括 ICMPA 协议和 ARP协议。ICMP 用于告知网络包传送过程中产生的错误以及各种控制消息, ARP 用于根据 IP 地址查询相应的以太网 MAC 地址
  • 网卡则负责完成实际的收发操作, 也就是对网线中的信号执行发送和接收的操作

套接字到底是什么

  • 在协议栈内部有一块用于存放控制信息的内存空间, 这里记录了用于控制通信操作的控制信息, 例如通信对象的 IP 地址、 端口号、 通信操作的进行状态等。 本来套接字就只是一个概念而已, 并不存在实体, 如果一定要赋予它一个实体, 我们可以说这些控制信息就是套接字的实体, 或者说存放控制信息的内存空间就是套接字的实体
  • 协议栈是根据套接字中记录的控制信息来工作的。比如发送数据时需要IP和端口号,等待回信时需要知道发送时间。
  • Windows 中可以用 netstat 命令显示套接字内容
    在这里插入图片描述

服务器一方的应用程序在启动时就会创建好套接字并进入等待连接的状态。 客户端则一般是在用户触发特定动作, 需要访问服务器的时候创建套接字。

调用 socket 时的操作

创建套接字的阶段

  • 协议栈首先会分配用于存放一个套接字所需的内存空间,然后向其中写入初始状态
  • 接下来, 需要将表示这个套接字的描述符告知应用程序
  • 收到描述符之后, 应用程序在向协议栈进行收发数据委托时就需要提供这个描述符。只要通过描述符确定了相应的套接字, 协议栈就能够获取所有的相关信息, 这样一来, 应用程序就不需要每次都告诉协议栈应该和谁进行通信了

在这里插入图片描述

连接服务器

连接要做什么

  • 客户端套接字刚刚创建完成的时候, 里面并没有存放任何数据, 也不知道通信的对象是谁。我们需要把服务器的 IP 地址和端口号等信息告知协议栈
  • 在服务器端,服务器也不知道要和谁通信,于是, 我们需要让客户端向服务器告知必要的信息
  • 连接过程还要分配临时存放要收发的数据的内存空间, 这块内存空间称为缓冲区

负责保存控制信息的头部

控制信息其实可以大体上分为两类

  • 第一类是客户端和服务器相互联络时交换的控制信息,
    • 这些控制信息位于网络包的开头, 因此被称为头部。 此外, 以太网和 IP 协议也有自己的控制信息, 这些信息也叫头部, 为了避免各种不同的头部发生混淆,我们一般会记作 TCP 头部、 以太网头部 B、 IP 头部
  • 控制信息还有另外一类, 套接字(协议栈中的内存空间)中记录的信息。

在这里插入图片描述

连接操作的实际过程

单次过程

  • 应用程序调用 Socket 库的 connect
  • 上面的调用提供了服务器的 IP 地址和端口号, 这些信息会传递给协议栈中的 TCP 模块
  • 在 TCP 模块处创建表示连接控制信息的头部。通过 TCP 头部中的发送方和接收方端口号可以找到要连接的套接字
  • 当 TCP 头部创建好之后, 接下来 TCP 模块会将信息传递给 IP 模块并委托它进行发送
  • IP 模块执行网络包发送操作后, 网络包就会通过网络到达服务器
  • 然后服务器上的 IP 模块会将接收到的数据传递给 TCP 模块
  • 服务器的 TCP 模块根据 TCP 头部中的信息找到端口号对应的套接字
  • 服务器的 TCP 模块会返回响应

三次握手

收发数据

什么时候发送

数据收发操作是从应用程序调用 write 将要发送的数据交给协议栈开始的,协议栈收到数据后执行发送操作协议栈收到数据先放在缓冲区,积累到一定量后才发送

判断要素

  • MTU:一个网络包的最大长度,以太网中一般为 1500 字节。
  • MSS:除去头部之后,一个网络包所能容纳的 TCP 数据的最大长度。
  • 时间:协议栈的内部有一个计时器, 当经过一定时间之后,就会把网络包发送出去
  • 应用程序亦可设定发送时机

在这里插入图片描述

对较大的数据进行拆分

在这里插入图片描述

确认机制

在这里插入图片描述
如何进行双向传输确认
在这里插入图片描述

重传机制

(即计算机网络笔记中的可靠传输部分)
方法

  • 自适应算法
    根据网络包平均往返时间调整 ACK 号等待时间
  • 冗余ACK确认,收到3个重发

更高效的收发方式

滑动窗口
在这里插入图片描述
流量控制

  • 让发送方发慢点,让接收方来得及接收
  • 接收方需要告诉发送方自己的接收缓存的大小,rwnd
    在这里插入图片描述

采用累计确认机制

接收 HTTP 响应消息

  • 浏览器在委托协议栈发送请求消息之后, 会调用 read 程序来获取响应消息。
  • 协议栈尝试从接收缓冲区中取出数据并传递给应用程序, 如果没来则将工作挂起,等收到消息再操作
  • 操作过程
    首先, 协议栈会检查收到的数据块和 TCP 头部的内容, 判断是否有数据丢失, 如果没有问题则返回 ACK 号。
    然后,协议栈将数据块暂存到接收缓冲区中, 并将数据块按顺序连接起来还原出原始的数据, 最后将数据交给应用程序

从服务器断开并删除套接字

连接释放
即TCP四次握手

  • 参与一条TCP连接的两个进程中的每一个都可以申请终止连接
  • 单方面释放连接表示本方无数据发送,但可接受,故要多次握手
  • 在四次握手的最后,返回ACK时候,需要等待一段时间之后再删除套接字,以防止ACK丢失重发后,套接字已经被删除的情况。

IP 与以太网的包收发操作

包基础知识

TCP 模块在执行连接、 收发、 断开等各阶段操作时, 都需要委托 IP 模块将数据封装成包发送给通信对象。生成数据包后,包会被发往最近的网络转发设备。

TCP/IP 包包含如下两个头部MAC 头部( 用于以太网协议)IP 头部( 用于 IP 协议)

两个头部在传输中的作用

  • IP 协议就可以IP地址查找包的传输方向, 从而找到下一个路由器的位置
    • 每经过一个路由器时,查IP协议表,就可以知道要发往哪个路由器
  • 查到下一路由时,IP 协议会委托以太网协议将包传输过去。这时, IP 协议会查找下一个路由器的以太网地址( MAC 地址), 并将这个地址写入 MAC 头部中。 这样一来, 以太网协议就知道要将这个包发到哪一个路由器上了。
  • 收到包的时候 MAC 头部会被舍弃,而当再次发送的时候又会加上包含新 MAC 地址的新 MAC 头部

包收发操作概览

  • TCP 模块委托 IP 模块发送包
    • 这个委托的过程就是 TCP 模块在数据块的前面加上 TCP头部, 然后整个传递给 IP 模块。与此同时,TCP 模块还需要指定通信对象的 IP 地址, 也就是需要写清楚“将什么内容发给谁”。
  • IP 模块会添加 IP 头部和 MAC 头部这两种头部
  • 接下来, 封装好的包会被交给网络硬件
    • 网络硬件可能是插在计算机主板上的板卡, 也可能是笔记本电脑上的 PCMCIA 卡, 或者是计算机主板上集成的芯片, 不同形态的硬件名字也不一样, 本书将它们统称为网卡
    • 网卡将数字信号0 1 转换为电信号或光信号, 并通过网线( 或光纤) 发送出去
  • 然后这些信号就会到达集线器、 路由器等转发设备, 再由转发设备一步一步地送达接收方网卡
    • 网卡将电信号转为数字信号并传递给 IP 模块
  • IP模块将数据包去掉IP头部后交给TCP模块,接下来的操作就是我们之前讲过的 TCP 模块负责的部分了

IP模板不关心包的内容,对所有包操作相同

生成包含接收方 IP 地址的 IP 头部

IP 地址实际上并不是分配给计算机的, 而是分配给网卡的

  • 计算机的 IP 地址” 这种说法并不准确。 一般的客户端计算机上只有一块网卡, 因此也就只有一个 IP 地址, 这种情况下我们可以认为这个 IP 地址就是计算机的 IP 地址, 但如果计算机上有多个网卡,情况就没那么简单了。 IP 地址实际上并不是分配给计算机的, 而是分配给网卡的, 因此当计算机上存在多块网卡时, 每一块网卡都会有自己的 IP 地址。 很多服务器上都会安装多块网卡, 这时一台计算机就有多个 IP 地址,在填写发送方 IP 地址时就需要判断到底应该填写哪个地址

Gateway(网关)在 TCP/IP 的世界里就是路由器的意思

生成以太网用的 MAC 头部

通过 ARP 查询目标路由器的 MAC 地址

  • ARP用来查IP 和MAC地址的映射关系
  • ARP有一个缓冲,有目标MAC地址,就不需要发送ARP查询没有的话,发送ARP查询,
  • ARP查询使用广播方式。
  • ARP缓冲隔几分钟就删除更新一次
  • 4种查询情况见计网笔记。

实际中,虽然MAC地址好像于IP无关,但是是让 IP 负责整个打包工作,这是有利的

以太网的基本知识

在这里插入图片描述三个性质

  • 尽管以太网经历了数次变迁, 但其基本的 3 个性质至今仍未改变,因此, 大家可以认为具备3 个性质的网络就是以太网
  • 将包发送到 MAC 头部的接收方 MAC 地址代表的目的地,
  • 用发送方 MAC地址识别发送方
  • 用以太类型识别包的内容。

将 IP 包转换成电或光信号发送出去

  • 负责执行这一操作的是网卡,网卡的 ROM 中保存着全世界唯一的 MAC 地址,这是在生产网卡时写入的。
  • 网卡中保存的 MAC 地址会由网卡驱动程序读取并分配给 MAC模块
网卡内部模块

在这里插入图片描述MAC模块

  • MAC 模块从报头开始将数字信息按每个比特转换成电信号
  • 以太网规格中对不同的网线类型和速率以及其对应的信号格式进行了规定, 但 MAC 模块并不关心这些区别,而是将可转换为任意格式的通用信号发送给 PHY( MAU) 模块

PHY(MAU)模块

  • PHY( MAU) 模块会将信号转换为可在网线上传输的格式,并通过网线发送出去
  • PHY( MAU) 的职责并不是仅仅是将 MAC 模块传递过来的信号通过网线发送出去, 它还需要监控接收线路中有没有信号进来
网卡对数据包操作

网卡工作

  • 报头的作用是确定包的读取时机
  • 起始帧分界符用来确定帧的起始位置
  • 末尾的 FCS( 帧校验序列) 用来检查包传输过程中因噪声导致的波形紊乱、 数据错误。它是一串 32 比特的序列,是通过一个公式对包中从头到尾的所有内容进行计算而得出来的

在这里插入图片描述

数据发送细节

发送方式

  • 加上报头、 起始帧分界符和 FCS 之后, 我们就可以将包通过网线发送出去了( 图 2.24)。 发送信号的操作分为两种, 一种是使用集线器的半双工模式, 另一种是使用交换机的全双工模式

半双工模式

  • 在半双工模式中, 为了避免信号碰撞, 首先要判断网线中是否存在其他设备发送的信号。如果有, 则需要等待该信号传输完毕, 因为如果在有信号时再发送一组信号, 两组信号就会发生碰撞
  • 和半双工有关的计网中的随机访问MAC协议(CSMA/CD CSMA/CA那些),轮询访问MAC协议(令牌)

根据以太网的规格, 两台设备之间的网线不能超过 100 米(这是双绞线的情况,如果采用光纤则可以更长,而且错误率不会上升) , 在这个距离内极少会发生错误,万一发生错误, 协议栈的 TCP 也会负责搞定, 因此在发送信号时没有必要检查错误。

接收返回包

  • 网卡将起始帧分界符后面的信号转换成数字信息。
  • 当到达信号的末尾时, 还需要检查 FCS。
    • 具体来说, 就是将从包开头到结尾的所有比特套用到公式中计算出 FCS, 然后和包末尾的 FCS 进行对比, 正常情况下两者应该是一致的, 如果中途受到噪声干扰而导致波形发生紊乱, 则两者的值会产生差异, 这时这个包就会被当作错误包而被丢弃
  • 如果 FCS 校验没有问题, 就检查MAC地址
    • 检查MAC 头部中接收方MAC 地址与网卡在初始化时分配给自己的 MAC 地址是否一致, 以判断这个包是不是发给自己的。 我们没必要去接收发给别人的包, 因此如果不是自己的包就直接丢弃, 如果接收方 MAC 地址和自己 MAC 地址一致, 则将包放入缓冲区中。
  • 接下来网卡会(通过中断操作)通知计算机收到了一个包。
  • 需要根据MAC 头部中的以太类型字段判断协议的类型,这样才能将包交给不同的协议栈

将服务器的响应包从 IP 传递给 TCP

服务器返回的包的以太类型应该是 0800, 因此网卡驱动会将其
交给 TCP/IP 协议栈来进行处理。

  • IP 模块。第一步是检查 IP 头部, 确认格式是否正确
  • 如果格式没有问题, 下一步就是查看接收方 IP 地址。(一般客户端不应该收到不是发给自己的包,而服务器也负责转发工作,就有可能出现这种情况)
  • 检查确认之后我们就可以接收这个包了,发生错误的话,IP 模块会通过 ICMP 消息将错误告知发送方。(询问报文、差错报文)
  • IP模块发送包时候采用了分片技术,如果收到分片的包,需要将分片的包还原成原来的包,然后交给TCP模块
  • TCP模块会根据 IP 头部中的接收方和发送方 IP 地址, 以及 TCP 头部中的接收方和发送方端口号来查找对应的套接字 A。 找到对应的套接字之后, 就可以根据套接字中记录的通信状态, 执行相应的操作了。看是连接的包还是通讯的包还是断开的包。(TCP为什么会负责IP头部,是因为实际工作中,这样做能提高效率)

UDP 协议的收发操作

不需要重发的数据用 UDP 发送更高效

大多数的应用程序都像之前介绍的一样使用 TCP 协议来收发数据, 但当然也有例外。 有些应用程序不使用 TCP 协议, 而是使用 UDP 协议来收发数据。

UDP使用场景举例

  • 向 DNS 服务器查询 IP 地址
  • 发送音频和视频数据
    • 音频和视频数据必须在规定的时间内送达, 一旦送达晚了, 就会错过播放时机,导致声音和图像卡顿。此外, 音频和视频数据中缺少了某些包并不会产生严重的问题, 只是会产生一些失真或者卡顿而已, 一般都是可以接受的

TCP为什么如何复杂

  • 因为我们需要将数据高效且可靠地发送给对方。
  • 为了实现可靠性, 我们就需要确认对方是否收到了我们发送的数据, 如果没有还需要再发一遍。(序号、确认、重传)
  • 为了实现高效的传输, 我们要避免重发已经送达的包, 而是只重发那些出错的或者未送达的包。 (滑动窗口、接收缓存、流量控制、拥塞控制)TCP 之所以复杂, 就是因为要实现这一点

UDP为什么简单

  • 但如果数据很短,一个包就能够装下,那也能实现高效的数据传输。因为如果只有一个包, 就不用考虑哪个包未送达了, 因为全部重发也只不过是重发一个包而已, 这种情况下我们就不需要 TCP 这样复杂的机制了。 而且, 如果不使用 TCP,也不需要发送那些用来建立和断开连接的控制包了。 此外,我们发送了数据,对方一般都会给出回复, 只要将回复的数据当作接收确认就行了, 也不需要专门的接收确认包了。

UPD收发简介

  • 只要在从应用程序获取的数据前面加上 UDP 头部, 然后交给 IP 进行发送就可以了。接收也很简单, 只要根据 IP 头部中的接收方和发送方 IP 地址,以及 UDP 头部中的接收方和发送方端口号, 找到相应的套接字并将数据交给相应的应用程序就可以了。 除此之外, UDP 协议没有其他功能了, 遇到错误或者丢包也一概不管。

UDP出错怎么办

  • 因为 UDP 只负责单纯地发送包而已, 并不像TCP 一样会对包的送达状态进行监控,但这样并不会引发什么问题, 因此出错时就收不到来自对方的回复,应用程序会注意到这个问题, 并重新发送一遍数据。 这样的操作本身并不复杂, 也并不会增加应用程序的负担。

视频使用TCP还是UDP探讨

  • 网页上的视频是基于HTTP/HTTPS,传输层是TCP
  • QQ视频聊天等是基于UDP
  • 甚至有的应用使用p2p协议,传输层应该也是TCP
  • 一方面,在网页上看视频可以忍受缓冲5s看到更清楚的视频,所以用TCP问题不大,在网络情况较好的情况下更是如此。视频聊天时绝不能容忍等待5s才听到对方的回话,所以用UDP更合适。使用TCP还是UDP是在网络条件有限的情况下对“实时性”和“传输质量”之间的权衡,不是必须用TCP或者UDP。

无连接服务与有连接服务

  • 面向连接服务就是在通信双方进行通信之前,必须先建立连接,在通信过程中,整个连接的情况一直被实时地监控和管理。通信结束后,应该释放这个连接
  • 无连接服务是指连个实体之间的通信不需要先建立好连接,需要通信时,直接将信息发送到网络中,让该信息的传递在网上尽力而为地往目的地传送
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

王蒟蒻

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

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

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

打赏作者

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

抵扣说明:

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

余额充值