通信层协议是进程到进程的通信
运输层的两个主要协议:
- 用户数据报协议UDP(User Datagram Protocol) (不可靠 非双向)
- 传输控制协议TCP (Transport Control Protocol) (可靠全双工)
应用层协议 | 运输层协议 |
---|
DNS | UDP |
TFTP(简单文件传送) | UDP |
RIP(路由信息协议) | UDP |
DHCP | UDP |
SNMP(简单网络管理协议) | UDP |
NFS(网络文件系统) | UDP |
IP电话 | UDP |
流式多媒体通信 | UDP |
多播 | UDP |
SMTP | TCP |
TELNET | TCP |
HTTP | TCP |
FTP | TCP |
运输层使用协议端口号来进行分发报文
TCP/IP协议中用了一个16位端口号(655356-1)来标志一个端口
两个进程间需要相互通信则必须知道对方的IP地址和端口号
端口号又分为:
TELNET:23
SMTP:25
DNS:53
TFTP:69
HTTP:80
SNMP:161
SNMP(trap):162
HTTPS:443
另一类是登记端口号:1024~49151
- 客户端端口号
常用:49152~65535 通信结束端口释放
UDP特点:
- 无连接
- 尽最大努力交付
- 面向报文(不存在粘包)
- 没有拥塞控制
- 支持一对一、一对多、多对一、多对多
- 首部开销小 8个字节 比TCP 20个字节短
UDP首部格式:
- 源端口
- 目的端口
- 长度 最小值是8(只有头部)
- 检验和 检测是否出错 出错则丢弃(与IP协议只检验头部不同的是,UDP检验头部和数据部分)
如果接送方收到报文中的目的端口号不正确、就丢弃该报文并且发送ICMP发送端口不可达的差错报文
TCP主要特点:
- TCP是面向连接的运输层协议(所以传输前要建立通信)
- 每一条TCP连接只能是点对对的
- TCP提供可靠交付(无差错、不丢失、不重复、并且按序到达)
- TCP提供全双工通信(都设有发送缓存、接收缓存)
- 面向字节流(每次发送的数据块都堆积在一起每次获取不一定都是发送的时候的块 因为发送速率不同(粘包的根本原因))
TCP连接的端点叫做套接字或插口
根据RFC793定义:端口号拼接到IP地址后就叫套接字
套接字socket = (IP地址:端口号)
可靠传输的工作原理
为什么需要可靠传输:
停止等待协议
A发送数据B接收到数据并发送确认,每发送完一个分组就停止发送在有限的时间内等待对方确认、如果指定时间内没有收到确认则重新发送报文,称之为超时重传。
实现的要点:
- 暂时保留已发送的分组的副本
- 分组和确认分组都必须进行编号
- 超时计时器 定义的超时时间应当比平均往返时间更长一些
当收到重复的报文,首先会丢弃这个分组然后再向客户端发送确认(因为之所以会重传是因为没有收到确认报文)
上述的协议称为自动重传请求ARQ(Automatic Repeat reQuest)
RTT(Round-Trip Time): 往返时延
发送方还可以不使用低效率的停止等待协议,可以一次性发送多个分组,然后再一次性的等待对方确认这就是连续ARQ协议和滑动窗口协议
连续ARQ协议
发送窗口:在发送队列中框起来的一个组、位于发送窗口内的分组连续发送出去不需要等待对方确认。
发送方每收到一个确认发送窗口向前滑动一个分组的位置,接收方只需要对【按序到达的的最后一个分组】发送确认,也就是说到此分组为止的所有分组已正确收到了。
但是这种协议也有缺点
比如:
A B C D E F
其中C报文漏了 那么就要发送窗口就要退到C的位置重新发送C D E F,如果通信信道不好的话此协议会带来负面影响
TCP报文段的首部格式
- 源端口和目的端口各占2字节
- 序号 占4字节 标记报文的序号
- 确认号 占4字节 标记下一个报文对应的序号
- 数据偏移 指的是数据段距离当前偏移多少也是数据报的开始位置
- 保留 占6位 目前未使用
- 紧急URG(URGent) 当URG = 1时 表明紧急字段有效 应尽快传送
- 确认ACK(ACKnowledgment) 仅当ACK=1 时确认号字段才有效。 在连接建立后所有传送的报文段必须把ACK置1
- 推送PSH(PuSH) 当置1时直接整个报文段发送出去而不用等缓存填满了再交付。
- 复位RST(ReSeT) 当RST = 1时 表示TCP连接中出现严重差错 必须释放连接重新建立连接
- 终止FIN 用来释放一个连接 当FIN=1时 表明此报文段的发送方的数据已经发送完毕要求释放链接
- 窗口 占2字节 从确认号算起 目前允许对方发送的数据量。
- 检验和 占2字节
- 紧急指针 占2字节 仅当URG = 1时才有意义 指出紧急报文段中紧急数据的字节数
- 选项 长度可变 最长可达40字节
- 时间戳 防止序号重用(一定时间内)、计算往返时间RTT
TCP滑动窗口
发送缓存:
- 发送应用程序传送给发送方TCP准备发送的数据
- TCP已发送但尚未收到确认的数据
接收缓存:
- 按序到达、但尚未被接收的应用程序读取的数据
- 未按序到达的数据
发送方A会根据网络的拥堵情况适当减小发送窗口数值
一般来说接收方会把未按序到达的数据暂时存储等缺的数据补齐了再上交应用层
接收方可以在合适的时间进行确认 不一定收到就要确认
一般确认推迟的时间不超过0.5秒
因为TCP是全双工通信所以通信双方都有发送窗口和接收窗口
选择确认SACK
实现只针对缺少序号的数据进行重发
如果要使用SACK算法要在TCP头部选项中加入 允许SACK 的选项
TCP的流量控制
让发送方的发送速率不要太快,让接受方来得及接收。
在连接建立时客户端向服务端告知客户端的滑动窗口大小
只有ACK=1 确认号字段才有意义
每次发送确认报文的时候并且会告知服务端窗口号大小假如窗口号为0然后过了一会窗口号又有位置发送给服务端告知服务端窗口号空余 假设这个数据报在传输的途中丢了的话 怎么办呢
为了解决这种情况每个TCP连接都有一个持续计时器 当收到零窗口的时候每隔一段时间发送一个零窗口的探测报文
TCP传输效率
确认TCP传输的时机算法广泛采用Nagle算法
算法归纳:
发送应用进程把发送的数据逐个缓存起来,发送方会把第一个数据字节先发送出去,把后面到达的数据字节先缓存起来当发送方收到第一个确认包的时候再发送缓存中的数据。还规定当到达的数据已达到发送窗口大小的一半或已达到报文段的最大长度则直接发送。
拥塞控制
拥塞控制与流量控制的差别:
拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
流量控制则是指点对点通信量的控制,是个端到端的问题
拥塞控制两种方法:
- 开环控制 设计网络时就事先将发生拥塞的因素考虑到
- 闭环控制 基于反馈环路
TCP拥塞控制方法
四种:
发送方维持一个拥塞窗口的状态变量cwnd(congestion window)
拥塞窗口大小取决于网络的拥塞程度 发送让自己的发送窗口等于拥塞窗口
检测是否拥塞:数据包有无确认(可能被路由器丢弃)
慢启动:由小到大逐渐增大发送窗口 每经过一次轮询拥塞窗口cwnd就加倍。
拥塞避免算法:让拥塞窗口cwnd慢慢增大 每次加1 而不是像慢启动那样成倍增加 我们首先是定一个门限值 当慢启动达到门限值时开始执行拥塞避免算法平滑的增加拥塞窗口直到出现网络超时则再对当前值/2等于新的门限值 以此类推
快重传:收到数据立即发送确认 接收方如果一连收到三个以上的重复确认则认定他的下一个数据报丢失了
接收方收到数据报会根据接收方情况重新设定接收方的拥塞窗口 rwnd
所以发送方窗口的大小为:min(cwnd,rwnd)
主动队列管理 AQM(Active Queue Management)
当路由器队列满了的时候后来到的数据包将会被丢弃,如果是TCP的数据包被丢弃那么发送方将会触发拥塞控制降低发送速率 导致利用率低,那么我们可以在路由器达到一定的值得时候就开始丢弃数据包而不用等到队列满了再丢弃。
AQM有不同的实现方法:
随机早期检测RED(Random Early Detection)
……
他的方法是 检测到网络拥塞的早期征兆(平均队列长度达到一定数值) 就以概率P丢弃个别的分组 让拥塞控制只在个别的TCP连接上进行 避免发生全局控制
TCP三次握手
1.首先创建传输控制块TCP
2.向B发送连接请求报文 SYN = 1 同时选择一个初始序号seq = x TCP规定SYN=1的报文不能携带数据只能发头部 进入SYN-SENT
3.B收到连接之后向A发送确认 SYN = 1 ACK(标志) = 1 ack(确认号)= x + 1 seq = y 进入SYN-RCVD
4.A收到B的确认后 ACK = 1 ack = y + 1 seq = x + 1 此报文可携带数据 如不携带数据则不消耗序号 A进入ESTABLISHED
5.B收到A的确认后也进入ESTABLISHED
为什么要三次握手 两次握手不行吗?
防止已失效的连接请求报文段突然又传送到了B 而产生错误
出现一种情况就是
A发出的连接请求报文因为网络节点而长时间滞留了,导致在连接释放后某个节点才到达B B收到了就误以为A又请求了 于是立刻建立连接。 采用三次握手可以防止上述情况发生
TCP四次挥手
1.A在报文上把终止位FIN = 1 seq = u u等于前面已传送过的最后一个字节的序号+1 A进入FIN-WAIT-1 FIN报文段即使不携带数据也消耗掉一个序列号
2.B收到了报文后返回ack = u+1 seq = v 等于B前面已发送过的数据的最后一个字节的序号+1 B进入了CLOSE-WAIT状态 TCP进入半关闭状态 即A没有数据要发送了也要接收B的数据 因为B到A的方向连接并未关闭
3.A收到B的确认后进入了FIN-WAIT-2 等待B发出的连接释放报文段
4.若B已经没有要向A发送的数据 其应用进程则通知TCP释放链接 B发出的连接FIN = 1 ack = u+1 B进入 LAST-ACK 等待A确认
5.A在收到B的连接释放报文后必须对此发送确认 ACK=1 ack = w+1 seq =u+1 然后进入time wait状态 等待时间计时器 设置的时间2MSL后 A才进入CLOSED状态 MSL 是最长报文段寿命(Maximum Segment Lifetime)
为什么要等待呢
- 为了保证A发送的最后一个ACK报文段能到达B 这个ACK报文段可能丢失因而使在LAST ACK状态的B收不到已发送的FIN + ACK报文的确认 B会超时重传FIN+ACK报文段 如果没有这个计时器那么有可能B就无法进入CLOSED状态
- 防止 已失效的连接请求报文段 出现在此
还要有一个保活计时器(keepalive timer) 防止客户端出现故障 还维护着这个链接 服务器每收到一次客户端的数据则刷新保活计时器 若没收到则要发送探测报文 如连续10个都没收到则关闭这个连接。