传输层(Transport)
- TCP(Transmission control Protocol), 传输控制协议
- UDP(User Datagram Protocol), 用户数据包协议

UDP (数据格式检验和)
UDP是无连接的, 减少了建立和释放连接的开销
UDP 尽最大能力交付, 不保证可靠交付, 因此不需要维护一些复杂的参数, 首部只有8 个字节. TCP 的首部至少20 个字节

UDP 长度(Length), 16 位, 首部长度+数据长度
检验和(Checksum)
检验和的计算内容: 伪首部+首部+数据
- 伪首部, 尽在计算检验和时起作用, 并不会传递给网络层

端口(Port)

UDP 首部中端口占用2 个字节, 范围是0~65535
客户端的源端口是临时开启的随机端口
防火墙可以设置开启或关闭某些随机端口, 提高安全性
常用命令如下
- netstat -an, 查看被占用的端口
- netstat -anb, 查看被占用的端口, 占用端口的应用程序
- tlenet 主机 端口, 查看是否可以访问主机的某个端口
TCP
要点:
- 可靠传输
- 流量控制
- 拥塞控制
- 连接管理(建立释放连接)

TCP 数据偏移, 保留
数据偏移
- 占4 位, 范围0b0101 ~ 0b1111
- 数据偏移 * 4 = 首部长度(Header Length)
- 首部长度, 20~60 字节
保留
- 占6 位, 默认全为0

UDP 首部中哟16 位的字段记录整个UDP 报文段的长度(首部 + 数据)
但是, TCP 首部中仅仅有个4 位的字段记录了TCP 报文段的首部长度, 并没有字段记录TCP 报文段的数据长度
-
UDP 首部中占16 位的长度字段是冗余的, 纯粹是为了保证首部是32 位对齐
-
TCP/UDP 数据长度, 完全可以由IP 数据包的首部对策出来
传输层的数据长度 = 网络层总长度 - 网络层的首部长度 - 传输层的首部长度
TCP 检验和(CheckSum)
跟UDP 一样, TCP检验和的计算内容: 伪首部 + 首部 + 数据
伪首部: 占12 字节, 尽在计算检验和时起作用, 并不会传递给网络层

TCP 标志位
URG(Urgent)
- 当URG = 1, 紧急指针字段才有效, 表明当前报文段中有紧急数据, 应优先尽快传送
ACK(Acknowledgement)
- ACK = 1, 确认号字段才有效
PSH(Push)
RST(Reset)
- RST = 1, 连接中出现严重差错, 必须释放连接, 然后再重新建立连接
SYN(Synchronization)
- SYN = 1, ACK = 0, 表明是一个建立连接的请求
- 若对方同意建立连接, 则回复SYN = 1, ACK = 1.
FIN(Finish)
- FIN = 1, 数据已经发送完毕, 要求释放连接
TCP 序号, 确认号, 窗口
序号(Sequence Number)
- 占4 个字节
- 在传输过程中, 每一个字节都有一个编号
- 建立连接后, 序号代表, 这一次传给对方的TCP 数据部分的第一个字节的编号
确认号(Acknowledgement Number)
- 占4 字节
- 建立连接后, 确认号代表, 期待对方下一次传过来的TCP 数据部分的第一个字节编号
窗口(Window)
- 占2 字节
- 这个字段有流量控制的功能, 用以告知对方下一次允许发送的数据大小(单位字节)
TCP 可靠传输
可靠传输是为了保证包的完整性, 当有丢包, 收到三次重复确认等情况, 就会重新发包
TCP 可靠传输 - 停止等待ARQ协议
ARQ(Automatic Repeat-reQuest), 自动重传请求


重传次数
若有包, 重传多次还是事变, 会一直重传到成功为止吗?
取决于系统设置, 比如重传5 次还是失败, 就会方发送reset报文(RST)断开TCP 连接

TCP 可靠传输 - 连续ARQ协议+滑动窗口协议

如果接收窗口最多能接收4 个包, 但发送只发了2 个包, 接收方如何确认后面还有无2个包?
- 等待一定时间后没有第3 个包, 就会返回确认收到2 个包给发送方

现在假设每一个组数据是100 字节, 代表一个数据段的数据, 每一个组给一个编号

TCP 可靠传输 - SACK(选择性确定)
在TCP 通信过程中, 如果发送序列中间某个数据包丢失. 如1, 2, 3, 4, 5, 丢失3
TCP 会通过重传最后确认的分组手续的分组. 最后确认为2, 重传3, 4, 5
这样原先已经正确传输的分组也可能重复发送, 降低了TCP 性能
为改善上述情况, 发展处SACK(Selective acknowledgement) 选择性确认技术
- 告诉对方哪些数据丢失, 哪些数据已经提前收到
- 使TCP 只重新发送丢失的包, 不用发送后续所有的分组

SACK 信息会凡在TCP 首部的选项部分
- Kind, 占1 字节, 值为5代表这是SACK 选项
- Length, 占1 字节, 标识SACK 选项一共占用多少字节
- Left Edge, 占4 字节, 左边界
- Right Edge, 占4 字节, 右边界

一对边界信息需要占用8 字节, 由于TCP 首部的选项部分最多40 字节, 所以
- SACK选项最多携带4 组边界信息
- SACK选最大占用字节, 4*8+2 = 34字节
为什么在传输层将数据分割, 而不是在网络层分割传递给数据链路层?
-
因为要提高重传的性能
-
可靠传输实在传输层进行控制的
如果在传输层不分段, 数据一旦丢失, 整个传输层数据都得重传
传输层分段后, 一旦部分数据丢失, 只需要重传丢失的那些段即可
TCP 流量控制
流量控制是点对点, 端对端, 两台设备之间的
如果接收方缓存区满了, 发送方还是疯狂发送数据
- 接收方智能把收到的数据包丢掉, 大量的丢包, 浪费网络资源
流量控制:
- 让发送方的发送速率不要太快, 让接收方及时处理数据
原理:
- 通过确认报文中的窗口字段来控制发送方的发送速率
- 发送方的发送窗口大小不能超过接收方的窗口大小
- 发送方收到接收窗口大小为0 时, 发送方就会停止发送数据
rwind(receive window), 接收窗口

TCP 流量控制 - 特殊情况
特殊情况:
- 一开始, 接收方给发送方发送0 窗口的报文段
- 后面, 接收方又有了一些存储空间, 给发送方发送的非0 窗口报文段丢失
- 发送方的发送窗口一直为0, 双方等待
解决:
- 当发送方收到0 窗口通知时, 这时发送方停止发送报文
- 同时开启定时器, 隔一段时间发送测试报文询问接收方最新的窗口大小
- 如还是0, 则发送方再次刷新启动定时器
TCP 拥塞控制

拥塞控制
- 防止过多的数据注入到网络中
- 避免网络中的路由器或链路过载
拥塞控制是一个全局的过程
- 涉及到所有的主机, 路由器
- 以及与降低网络传输性能有关的所有因素
TCP 拥塞控制方法
- 慢开始(slow start)
- 拥塞避免(congestion avoidance)
- 快速重传(fast retransmit)
- 快速回复(fast recovery)
概念:
- MSS(Maximum Segment Size), 每个段最大的数据部分大小(建立时确定), 一般是MTU(1500) - 20 - 20 = 1460
- cwnd(congestion window), 拥塞窗口
- rwnd(receive window), 接收窗口
- swnd(send window), 发送窗口. swnd = min(cwnd, rwnd)
TCP 拥塞控制 - 慢开始
cwnd的初始值比较小, 随着数据包被接收方确认(收到一个ACK), cwnd 就成倍增长(指数级)


TCP 拥塞控制 - 拥塞避免

ssthresh(slow start threshold), 慢开始阈值, cwnd达到阈值后, 开始拥塞避免
拥塞避免(加法增大), 拥塞窗口cwind 缓慢增大, 以防止网络过早出现拥塞
乘法减小, 只要出现网络拥塞, 把ssthresh 减为拥塞峰值一半, 同时执行慢开始, 当网络出现频繁拥塞时, ssthresh 值下降很快
TCP 拥塞控制 - 快重传, 快恢复

快恢复:
当发送方连续收到三个重复确认, 说明网络出现拥塞
- 执行乘法减小, 把ssthresh 减为拥塞峰值的一半
与慢开始不同之处是现在不执行慢开始算法, 即cwnd 现在不回复到初始值
- 把cwnd 值设置为新的ssthresh值
- 开始执行拥塞避免算法(加法增大), 使拥塞窗口缓慢的线性增大

发送窗口的最大值swnd = min(cwnd, rwnd)
当rwnd < cwnd时, 是接收方的接收能力限制发送窗口的最大值
当cwnd < rwnd时, 网络拥塞控制发送窗口的最大值
TCP 序号, 确认号







TCP 建立连接 - 3 次握手

- CLOSED, client处于关闭状态
- LISENT, server处于监听状态, 等待client连接
- SYN-RCVD, server接收到了SYN 报文, 当收到client 的ACK 报文后, 进入到ESTABLISHED 状态
- SYN-SENT, client已发送SYN 报文, 等待server 的第二次握手
- ESTABLISHED, 已经建立连接
TCP 建立连接 - 前2 次握手的特点
SYN 都为1,
数据部分长度都是0
TCP 头部长度一般为32 字节
- 固定头部, 20 字节
- 选项部分, 12 字节
双方交换确认一些信息
- 比如MSS, 是否支持SACK, Window scale(窗口缩放系数)
- 这些数据存放在TCP 头部选项部分(12 字节)
为什么是3 次握手不是2 次?
目的: 防止server 端一直等待, 浪费资源
如果建立连接只需要2 次握手, 可能出现以下情况
- 假设client 发出的第一个连接请求报文段, 因为网络延迟, 在连接释放以后的某个时间才到server, 本来是一个早已经失效的连接请求, 但server 收到这个请求后, 误认为client 再次发出的一个新的连接请求, server 向client 发出确认报文段, 同意建立连接
- 如果上述不采用3 次握手, 那么只要sever 发出确认, 新的连接就建立了
- 由于是一个失效的连接请求, client 并没有建立与服务器连接的意愿, 也不会向server发送数据. 但是server 却认为新的连接已经建立, 并一直等待, server很多资源就白白浪费了
第三次握手失败的处理
- 此时server 的状态为SYN-RCVD, 若等不到client 的ACK, server 会重新发送SYN-ACK包
- 若server 多次重复发哦送SYN-ACK都等不到client 的ACK, 就会发送RST, 强制关闭连接

TCP 释放连接 - 4 次挥手

FIN-WAIT-1, 表示主动关闭连接
- 向对方发送FIN 报文, 此时进入到FIN-WAIT-1 状态
CLOSED-WAIT, 表示在等待关闭
- 当对方发送FIN 给自己, 自己会回应一个ACK 报文给对方, 此时则进入到CLOSED-WAIT状态
- 在此状态下, 需要考虑自己是否还有数据发送给对方, 如果没有, 发送FIN 报文给对方
FIN-WAIT-2, 只要对方发送ACK 确认后, 主动方就会进入FIN-WAIT-2 状态, 然后等待对方发送FIN 报文
CLOSING, 罕见状态
- 表示你发送FIN 报文, 并没有收到对方ACK, 反而收到对方FIN 报文
- 如果双方几乎同时准备关闭连接的话, 那么久出现双方同时发送FIN 报文的情况, 也会出现CLOSING状态
- 双方都在关闭连接
LAST-ACK, 被动关闭一方在发送FIN 报文后, 最后等待对方的ACK 报文
- 当收到ACK 报文后, 即可进入CLOSED 状态
TIME-WAIT, 表示收到对方的FIN 报文, 并发送出了ACK 报文, 就等待2MSL 后进入CLOSED状态
- 如果FIN-WAIT-1 状态, 收到对方同时带FIN 标志和ACK 标志的报文, 可以直接进入到TIME-WAIT 状态, 无需经过FIN-WAIT-2
CLOSED, 关闭状态
由于有些状态的时间比较短暂, 所以很难用netstat 命令看到, 比如SYN-RCVD, FIN-WAIT-1
TCP 释放连接 - 细节
-
client 发送ACK 后, 需要有个TIME-WAIT 阶段, 等待一段时间, 再关闭连接
一般是等待2 倍MSL(Maximum Segment Lifetime), 最大分段生存期
MSL 是TCP 报文在Internet 上的最大生存时间
每个具体的TCP 实现都必须选择一个确定的MSL, RFC 112 建议2 分钟. 可以防止本次连接中产生的数据包误传到下一次连接中, 因为本次连接中的数据包会在2MSL 时间内消失了
-
如果client 发送ACK 后马上释放了, 然后因为网络的原因, server 没有收到client 的ACK, server就会重发FIN, 这时可能出现的情况是
- client 没有任何响应, 服务器那边一直等待, 甚至多次重发FIN, 浪费资源
- client 有新的应用程序刚好分配同一个端口号, 新的应用程序收到FIN 后马上开始执行断开连接的操作, 原本是要和server 建立连接的
为什么进行4 次挥手?
TCP 是全双工通信
第一次挥手, 主机1 发出FIN 报文时
- 主机1 告诉主机2 没有数据要发送了, 但是主机1 还是可以接收主机2发来的数据
第二次挥手, 主机2 返回ACK 报文
- 主机2 已经知道主机1 没有数据发送了, 但是主机2 还是可以发送数据到主机1
第三次挥手, 主机2 也发送FIN 报文
- 主机2 告诉主机1, 主机2 已经没有数据要发送了
第四次挥手, 主机1返回ACK报文
- 主机1 已经知道主机2 没有数据发送了, 随后正式断开整个TCP 连接
网友评论