TCP / IP 协议(一)
1. 应用层
应用程序
2. 传输层
负责数据能够从发端传输到接收端
五元组:
协议号 + 源 IP + 源 port + 目的 IP + 目的 port
- 协议: 网络数据传输时, 经过的网络节点约定的规则, 最终体现为数据格式
- 端口号: 主机中的进程, 绑定进程
- IP: 在网络层IP 协议中包含 ip 地址这个字段, 体现为起点和终点, 绑定主机
2.1 UDP 协议
UDP 特性:
- 无连接, 不可靠 (要保持连接, 意味双方保持一个连接状态)
- 面向数据报 (发送和接受, 都只能一次完成)
- 有接受缓冲区, 没有发送缓冲区 (发送发不关心对方是否收到, 接受方可以接受多个udp数据)
- 发送数据大小受限 (最多 64k)
基于UDP的应用层协议:
- TFTP: 简单文件传输协议
- DNS: 域名解析协议
2.2 TCP 协议
TCP 设计原则: 网络数据传输, 在保证安全的前提下, 尽可能提高传输效率
- ACK: 确认号是否有效
- SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段
- FIN: 通知对方, 本端要关闭了, 我们称携带FIN标识的为结束报文段
2.2.1 TCP 安全机制
2.2.1.1 确认应答(ACK)机制
TCP将每个字节的数据都进行了编号. 即为序列号.
每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始
发.
2.2.1.2 超时重传机制
基于确认应答机制的不足 (没有收到应答, 不能一直无限期的等待)
- 发送的数据丢包
- 应答数据丢包
在一定时间范围内, 如果没有接收到应答数据报, 就要重发
超时时间: 受网络带宽等环境因素影响
在主机未收到ACK时
因此主机会收到很多重复数据, 那么TCP协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉.
这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果.
2.2.1.3 连接管理机制
什么是连接?
主机 A 和主机 B , 都持有本端到对方的连接状态(有方向)
主机A 发送数据, 到连接到 ack 确认应答的数据报, 只表示主机 A 能正常传输数据到主机 B , 但主机B 到主机A 是不确定的
(1) 三次握手的流程 (建立连接)
- 客户端发送 SYN(建立连接的标志位) + SEQ_NO(序号) 到服务端
这里的 SYN 是客户端到服务端的连接 (申请建立, 要返回ack以后, 才是真正的建立) - 服务端响应 SYN, ACK(应答第一个步骤的 SYN), SEQ_NO+1(确认序号) 到客户端
这里的 SYN 是服务端到客户端的连接 - 客户端再响应 ACK 到服务器, 服务端接受到以后, 建立服务到客户端的连接 (服务端保存这个连接状态), 连接建立( 保持连接状态)
是有方向的
为什么是三次?
第二次服务端返回 SYN + ACK , 是可以合并的(只是标志位设置就行)
(2) 四次我握手的流程(关闭连接)
- 客户端发送 FIN 到服务器, 申请关闭连接 (客户端到服务器的连接状态), 服务端状态设置为 CLOSE_WAIT
- 服务端响应 ACK
- 服务端发送 FIN 到客户端, 申请关闭连接 (服务端到客户端的连接状态), 客户端接收到, 状态设置为TIME_WAIT
- 客户端响应ACK, 服务端接收到以后, 服务端关闭连接
注意:
-
第三步客户端没有直接设置为CLOSED关闭连接?
第四步的ACK 可能丢包, 所以要等待一下(超时重传) -
为什么第二步和第三步, 没有建立连接时, 合并数据包?
第二步是系统对TCP协议的实现, 接受 FIN , 自动返回ACK, 不再执行程序代码
第三步是程序手动调用执行,(服务端关闭连接前, 需要执行一些前置工作)
一般而言,对于服务器上出现大量的 CLOSE_WAIT 状态, 原因就是服务器没有正确的关闭 socket, 导致四次挥手没有正确完成. 这是一个 BUG. 只需要加上对应的 close 即可解决问题.
2.2.1.4 流量控制
接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端
继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应.
因此TCP支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫做流量控制
2.2.1.5 拥塞控制
作用: 发送端不清楚网络状态时, 采用慢启动机制, 先探探路, 再决定发送数据的速度
TCP引入 慢启动 机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据;
拥塞窗口: 窗口的大小, 标识发送端网络状态
刚开始拥塞窗口大小= 1; 以先慢后快 (2的指数曲线) 增长方式变大, 到达阈值后, 变为线性增长, 最终到达网络拥塞 (大量丢包) 后, 窗口大小重置= 1; 重复以上过程
2.2.2 TCP 提高效率的机制
2.2.2.1 滑动窗口
可以基于多线程并发, 并行的指向代码
使用滑动窗口, 就是同时收发多条数据报
响应的ack, 下一个序号是多少, 代表的意思, 接受端在这个序号前的数据包, 已经接收到了
- 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值(发送端, 接收到ack确认序号的最大值).上图的窗口大小就是4000个字节(四个段).
- 操作系统内核为了维护这个滑动窗口, 需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答; 只有确认应答过的数据,才能从缓冲区删掉;
- 窗口越大, 则网络的吞吐率就越高;
窗口的大小受限于流量控制窗口大小和拥塞窗口大小 = min (流量窗口大小, 拥塞窗口大小)
滑动: 接收到 ack 确认序号的最大值, 可以计算出多少段数据对方已经接受到, 对应的发送端滑动窗口, 就向下活动多大
2.2.2.2 延迟应答机制
作用: 接收端稍等一定的时间再应答, 这样程序就可以有时间消费掉接收缓冲区的数据, 接收缓冲区剩余空间就更大, 返回的流量窗口就更大
延迟的条件:
- 数量限制: 每隔N个包就应答一次;
- 时间限制: 超过最大延迟时间就应答一次;
2.2.2.3 捎带应答
2.2.2.4 面向字节流
创建一个TCP的socket, 同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区;
- 调用write时, 数据会先写入发送缓冲区中;
- 如果发送的字节数太长, 会被拆分成多个TCP的数据包发出;
- 如果发送的字节数太短, 就会先在缓冲区里等待, 等到缓冲区长度差不多了, 或者其他合适的时机发送出去;
- 接收数据的时候, 数据也是从网卡驱动程序到达内核的接收缓冲区;
- 然后应用程序可以调用read从接收缓冲区拿数据;
- 另一方面, TCP的一个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这一个连接, 既可以读数据, 也可以写数据. 这个概念叫做全双工
2.2.2.5 粘包问题
发送和接受, 都存在缓冲区; (多次发送和接受)
原因: 解析某个数据是, 用到了其他部分数据了
TCP 是基于字节流的, 多数据报在缓冲区, 存在粘包问题, UDP 是一次发, 一次读, 不存在粘包问题
安全性, 可靠性机制:
- 确认应答
- 超时重传
- 连接管理
- 流量控制
- 拥塞控制
提高效率的机制
- 滑动窗口
- 延时应答
- 捎带应答
基于TCP 的应用层协议:
- HTTP
- HTTPS
2.3 TCP 和 UDP 区别
没有哪个更好, 只有在某个具体的业务场景中, 更适合的选择
如果要满足安全可靠(包括次序) 就要使用 TCP , 反之, 可以使用 UDP
- 效率看, UDP 更优 (不用等待 ACK 应答)
- UDP 无连接, 不可靠; 反之 TCP 有链接, 可靠地传输
- UDP 是面向数据报, 只能一次发送和一次接受; TCP 是面向字节流的, 可以多次收发
- UDP 具有节后缓冲区, 没有发送缓冲区, TCP 则都有
- UDP 大小受限, TCP 不受限
- TCP 有确保安全传输的机制