本文主要内容来自 SpriCoder的博客,更换了更清晰的图片并对原文的疏漏做了补充和修正。
第四层运输层主要是实现了主机之间的通信,数据通信是服务于主机上的会话进程(Session)。
第四层综述
第四层执行多项功能:
- 分割上层应用程序数据(新的数据单元-数据段),第四层只会在终端设备上有,在中间设备没有
- 建立端到端(end to end)的运营
- 从一个终端主机向另一个终端主机发送 segments(第三层和第二层不进行可靠性检验,第四层完成可靠性检验,接受方认为数据错误,在第四层进行要求重传)
- 流量控制和可靠性:可以比喻为与外国人交谈:通常,您会要求外国人重复他/她的话(可靠性)并慢声说话(流量控制),因为双方主机的网络的处理能力不同,缓存能力不同
两个特别重要的第四层协议:
- 传输控制协议(TCP,Transmission Control Protocol),是可靠传输
- 用户数据报协议(UDP,User Datagram Protocol)
将传出邮件分成多个部分,在目标站重新组合消息
TCP:可靠(效率比较低,早期网络应用少,需要可靠性)
- 面向连接(通信之前需要三次握手建立连接关系,通信过程中也需要检查连接是否断开,连接可靠性是否发生变化等),使用确认机制,提供流量控制
- 软件检查段(segment)
- 重新发送丢失或错误的任何内容
UDP:不可靠
- 无连接,不使用确认,不进行流量控制
- 不提供用于细分的软件检查
- 直接丢弃错误的报文,而不进行其他操作。
SCTP(Stream Control Transmission Protocol):流控制传输协议,为了进行视频和音频的传输
服务模型
- TCP 和 UDP 都使用端口来跟踪(track)同时穿越网络的不同会话(即不同进程)
- 应用软件开发人员已同意使用 RFC1700 中定义的知名端口号
端口分配规范
- 低于 255 的端口号(0-255)保留给 TCP 和 UDP 公共应用程序使用(端口号 0-255 是 public 的,不可以随意分给其他的进程,如果分发则不符合规范)
- 0-1023 是熟知端口,有分发的规范,不应当被随意使用
- 1024-49151 的端口号进行登记使用,有的是应用程序已经的使用端口号,避免冲突
- 49152-65535 即为短暂端口号,用于和远端通信
- 基于端口号的不同,进行不同的包的分发
套接字(Socket,第四层的单位)
第四层进行通信的单位是进程,由 IP 和端口共同指定。socket 是第四层的地址
- 套接字表示为(IP 地址,端口)
- 每个连接都表示为(socket source ,socket destination ),点对点全双工通道
- 通讯被认为是以一个 socket 和另一个 socket 之间的连接(Socket API 是一套规范,根据上下文有不同的含义)
- TCP 不支持多播和广播
传输控制协议 TCP
TCP 必须解决的问题
- 可靠传输
- 流传输
- 流量控制:滑动窗口(窗口进行通信,一次数据传输是有上限发的,缓存问题,拥塞问题)
- 避免拥塞
- 连接控制
- 建立连接:三次握手
- 断开连接:四次握手
TCP 数据段的格式
首部情况
一行共计 4 字节,段首在前,固定首部长度为 20 字节。
源端口和目的端口
源端口和目的端口字段:各占 2 字节
- 端口是运输层与应用层的服务接口
- 运输层的复用和分用功能都要通过端口才能实现
序号字段
序号字段:占 4 字节(4G = \(2^{32}\))的地址空间)
- TCP 传送的数据流中的每一个字节都编上一个序号
- 序号字段的值指本报文段所发送的数据的第一个字节的序号
- 通过序号字段做可靠传输的保证,指示的是一个 TCP 传输的比特编码,而不是地址
- 我们从小向大进行使用,如果使用到最大之后,我们会从小再次重新开始分配
确认号字段
确认号字段:占 4 字节,是期望收到对方的下一个报文段的数据的第一个字节的序号
- 确认对方的数据号(发送同时对上一次传输进行确认)
- 体现出了全双工通信的优点,比如上回收到最后序号是 700,那么确认号就是 701
数据偏移
数据偏移(即首部长度):占 4 位
- 指出 TCP 报文段的数据起始处距 TCP 报文段的起始处的长度(Data 部分从什么地方开始算)
- 单位是 32 位字(以 4 字节为计算单位)
- 不满足的话使用填充位保证为 4 字节的整数倍(保证对齐问题)
保留字段
保留字段:占 6 位,保留为今后使用,目前置 0, 也就是说截止到现在也没有使用这部分的字段。
URG
紧急 URG = 1 时,表明紧急指针字段有效。
- 告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)
- 优先放紧急数据,URG = 0 的时候则为不紧急(Ctrl + Z)
ACK
ACK = 1 时确认号字段有效;ACK = 0 时确认号字段无效
PSH(PuSH)
- 接收 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付,此时将缓存所有部分都传输,而并不是只将这个报文段的信息进行传输。
- TCP 在正常条件下并不是立马传输的,首先要缓存满了才发送,其次还有就是要保证网络可信的时候才发送
RST
- ReSeT = 1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接
- 就是重新来过,如果请求方发送的请求,如果应答方不想连接则将 ReSet 置为 1
SYN
同步 SYN = 1:表示这是一个连接请求或连接接受报文(初始的时候才出现)
FIN(FINish)
用来释放一个连接。FIN = 1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。(发送方没有传输数据了)
断开连接有四次握手。
窗口
- 占 2 字节,用来让对方设置发送窗口的依据,单位为字节。
- 表示可以进行传输的窗口大小是多少,即告诉接收方最多能发给我多长的数据
检验和
检验和:占有 2 字节。
- 检验和字段检验的范围包括首部和数据这两部分
- 2 字节,IP 报文中的地址等伪首部进行校验
紧急指针字段
紧急指针字段:占有 2 字节。
指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)
选项
- TCP 最初只有一种选项,即最大报文段长度 MSS(Maximum Segment Size)
- MSS 告诉对方缓存所能接收的报文段的数据字段的最大长度是 MSS 个字节
- 数据字段加上 TCP 首部才等于整个的 TCP 报文段
填充字段
填充字段:这是为了使整个首部长度是 4 字节的整数倍。
TCP 协议
- 主机使用网段(TPDU)交换数据
- 每个段都有:首部为 20 个字节(可选部分除外)+ 0 或更多数据字节(请求连接的时候)
- 段的大小必须与 IP 数据包匹配,并且还必须满足底层的需求
- 例如,以太网的 MTU(最大传输单位)为 1500 字节
- 是面向字节的传输。
- 每个字节都有一个 32 位序号
- 通讯中商定初识序号,确认到每一位
- 面向字节:TCP 传输的数据块和上层数据给的数据块的大小可以不对应(通过协商解决)
- 根据网络条件,对每一个字节进行确认,
可靠连接
- 红蓝两军问题
- 两军之间传输信息,由侦查员进行传递
- 结论:无论通信多少次,都不能确定一个完全可信的时间。
TCP:建立可靠连接
建立可靠连接(Establish Connection)
第一次握手
- 服务器:执行 LISTEN 和 ACCEPT 原语(primitive),并进行被动监视
- 客户端:执行 CONNECT 原语,生成 SYN = 1 和 ACK = 0 的 TCP 段,代表连接请求
第二次握手
服务器检查是否存在监视端口的服务进程
- 如果没有任何进程,请使用 RST = 1 回答一个 TCP 段
- 如果存在进程,则决定拒绝或接受请求
- 如果接受连接请求,则发送 SYN = 1 和 ACK = 1 的网段
第三次握手
- 客户端发送一个 SYN = 0 和 ACK = 1 的段以确认连接
- 为了避免出现延时之类的情况(如果只有两次会浪费服务器资源)
通知上层应用,准备数据传输
服务器收到确认后,会通知上层应用程序。
- 默认三次握手就认为可靠了,之后就进行数据传输
- 有时候我们会选择,第三次握手的时候同时携带数据。
建立连接实例
- 用于连接同步(Synchronization)的基本三次握手
- 请注意,ACK 不会占用序列号空间(if it did, we would wind up ACKing ACK's!)
停止等待协议
- 发送段后,暂时保留备份
- 在发送后没有收到确认的时候,要保存备份来重传
- 收到确认的时候,抛弃备份
- 超时计时器:如果对方的应答超过一定时间后则直接进行重发(时间要比正常往返时间稍微长一点)
- 每个网段和 ACK 必须具有 ID
- 重新发送时间必须大于平均传输时间 * 2
- 停止等待协议是一个简单的协议,但是效率很低
- 实施控制,来进行错误处理
数据传输 - 丢失确认和确认延迟
- 发过去没有应答或者丢失:进行重传
- 应答超时,有收到请求立即重传
- 晚到的应答直接丢弃(不做处理)
可靠通信
自动重传请求(Automatic Repeat reQuest,ARQ):这表示“重新发送请求”为自动发送并且接收方无需请求发送方重新发送错误段
连续 ARQ 协议
连续 ARQ 协议(Contiguous ARQ Protocol)
- 多个数据同时发送过去(一次发送多个)
- 窗口大小是双方协商的,通过 TCP 报文中的窗口字段表示。
ARQ 具体实例
- 发送端要发送 900 字节长的数据,划分为 9 个 100 字节长的报文段,而发送窗口确定为 500 字节。
- 发送端只要收到了对方的确认,发送窗口就可前移。
- 发送 TCP 要维护一个指针。每发送一个报文段,指针就向前移动一个报文段的距离。
- 发送端已发送了 400 字节的数据,但只收到对前 200 字节数据的确认,同时窗口大小不变。
- 现在发送端还可发送 300 字节。
- 发送端收到了对方对前 400 字节数据的确认,但对方通知发送端必须把窗口减小到 400 字节。
- 现在发送端最多还可发送 400 字节的数据。
- 利用可变窗口大小进行流量控制双方确定的窗口值是 400
- WIN:窗口的大小:双方动态协商,收到确认调整窗口
- ACK:是指可以继续发送的数据的位置。
- 为什么 201 在 401 后面发送?超时重传(要超过两倍的平均传输时间后才进行重传)
TCP:释放链接
- 发起断开连接请求
- Ack = 1:允许断开,但是此时并不是断开连接,而是说不在发送新的数据,此时我们需要完成之前未处理完成的数据的处理。(这里只是说我已经收到了你请求停止传输的请求)
- FIN = 1:数据处理完成,注意需要的变化(此时表示所有的需要处理的数据已经处理完了,此时表示正式确认断开)
- 确认收到 B 的断开信息
- 上图是释放连接的汇总
- 等待最大的网路往返时间(保证能处理到 B 最后发送的报文)
为什么必须等待 2 MSL
- 为了确保 A 发送的最后一个 ACK 可以到达 B
- 防止出现任何无效的连接请求段:等待 2 MSL 之后,我们可以确保连接上的所有段均已消失
TCP 中的计时器
- 重传计时器:多长时间进行重传
- 坚持计时器:避免死锁(WIN = 0 的时候修改 WIN 但是没有办法发送过去):收到 WIN = 0 的时候,开始进行计时,到时间主动询问
- 保持计时器:
- 发送数据段后,刷新
- 如果到达一定的时间,则再次询问是不是还要保持连接
- 时间等待计时器
TCP 的有限状态机
- 粗线:正常的服务器端
- 虚线:正常客户端
- 细线:异常状态的问题
用户数据报协议 UDP
用户数据报协议 UDP
用户数据报协议(User Datagram Protocol)
- 为什么我们需要 UDP?
- 没有建立连接(避免延时)
- 简单:发送方,接收方无连接状态
- 小段标题
- 没有拥塞控制:UDP 可以按照期望的速度传输
- 无连接:没有复杂控制,头部简单
- UDP 发送方,接收方之间没有握手(HandShake,包含进程等信息的)
- 每个 UDP 段都独立处理
- 常用于流媒体(Stream)多媒体(multimedia)应用
- 容忍损失:无非就是降低帧率
- 这类应用是速率敏感的应用,而不一定是质量敏感的应用。
- UDP 用于:
- RIP:定期发送路由信息(periodically)
- DNS:避免延迟建立 TCP 连接(DNS 需要快速找到)
- SNMP:拥塞时(congestion),SNMP 必须仍然可运行。在没有拥塞和可靠性控制机制的情况下,UDP 在这种情况下的性能要优于 TCP。(主播和多播,大量信息传输)
- 其他协议包括 TFTP,DHCP
- 必要时增加应用层的可靠性
- 流媒体就算有数据丢失也问题不大(对屏幕进行模糊化处理就行),但是发送速率是很重要的!(就算丢包了,也可以模糊处理)
UDP 数据帧格式
- UDP 的数据段很简单
- UDP 只有 8 个字节的首部,所以 UDP 报文最少是 8 个字节
- 源端口、目的端口、长度(包括 header 长度)、校验(data)、Data
- 校验也要对 data 一并校验,如果出现错误,直接丢弃。
- 应用层进行数据切片,决定如何进行发送,UDP 直接发送,UDP 不会再自己分片了
TCP 和 UDP 的不同
TCP
- 不是立即交给上层校验,而是需要先和对方沟通
- 缓存满了才统一交付。
UDP
- 直接转发报文,保留报文边界
- IP 进行划分
- 应用程序会发送比较合适的 UDP 报文大小进行发送
共同点
- 校验是相同的。
应用:NAT 和 PAT
什么是 NAT?
NAT(Network Address Translation),是在 IP 数据包头中将一个地址交换为另一个地址的过程
- 网络地址转换
- 是网络地址即将用完的解决方案
实际上,NAT 用于允许私下寻址的主机访问 Internet。NAT 是 IP 地址耗尽的解决方案之一:
- 保留注册(合法)地址
- 连接到 Internet 时增加灵活性
NAT 技术是一个简单的概念
- NAT 需要一个路由器来实现
- 左侧是一个局域网
- 在 NAT 路由器将局部地址转换成网络上的地址(双向转换,有一个 NAT 表)
NAT 的类型
- 静态 NAT:固定的内部地址(internal address)到注册地址(registered address)的映射(一开始就写死)
- 动态 NAT:映射以先到先得的方式动态进行(不是写死,配一个地址池,通过更新)
- PAT(过载,Port address translation):端口地址转换用于允许许多内部用户共享一个“内部全局”地址(基于 Socket 映射,而不是 IP 地址,多个内网主机映射到一个公网地址)
NAT 地址类型
- Inside Local address(内部本地地址):内网 IP 地址
- Inside Global address(内部全局地址): 注册 IP 地址, 对外部展示的内部地址
- Outside Global address(外部全局地址):由主机所有者分配的 IP 地址。通常是注册地址。(对内网而言的外部,是目的地址)
- 三个地址在上面可以看一下
- 内部主机发送报文给网关,网关根据 NAT Table 进行翻译,转换成内部全局地址,然后进行转发
静态 NAT 的例子
动态 NAT 的例子
NAT 的优点和缺点
- 优点:由于并非每个内部主机都需要同时进行外部访问,因此您可以使用少量的全局唯一地址池来服务相对大量的私有寻址主机。
- 缺点:一一映射,并没有从根本上解决地址短缺的问题。
也就是说,如果专用地址空间为 /8,但公用地址为 /24,则一次只能有 254 个主机可以访问 Internet,主要内网不是同时有很多主机上网,就可以如上操作,进一步降低地址压力(类似并行和穿行的区别)
PAT 的工作原理
- 第一个是 IP
- 可以有不同的端口
- 同样的出口 IP,用不同的端口号来区别
PAT 操作
我们对路由器的端口信息进行了调整,使得内网的 socket 和外网的 socket 可以建立通信。