传输层提供的功能如下
- 提供应用进程之间的逻辑通信,即端到端的通信。
- 复用和分用。复用是指发送方不同的应用进程都可以使用同一个传输层协议传送数据,分用是指接收方的传输层能够把数据正确交付到目的应用进程。
- 对收到的报文进行差错检测(首部和数据部分)。
传输层提供了两个传输协议
- 一个是面向连接的传输控制协议(TCP),采用 TCP 时,传输层向上提供的是一条全双工的可靠逻辑信道;
- 一个是无连接的用户数据报协议(UDP),采用 UDP 时,传输层向上提供的是一条不可靠的逻辑信道。
TCP
TCP 提供面向连接的服务,在传送数据之前必须要建立连接,并在内核中为该连接维持一些必要的数据结构,比如连接的状态、读写缓冲区以及诸多定时器等。待数据传送结束后要释放连接。由于 TCP 提供可靠的传输服务,因此不可避免地增加了许多开销,如序号、确认号、应答确认、流量控制、拥塞控制、超时重传、定时器及连接管理等机制,导致协议数据单元的头部增加了许多,还会占用 CPU 的很多资源;另外,由于 TCP 报文最终是以 IP 数据报发送的,而 IP 数据报到达接收端可能乱序、重复,因此 TCP 会对接收到的 TCP 报文段重排、整理,再交付给应用层。TCP 适用于对可靠性、数据的传输质量要求高,但对实时性要求不高的场景,如文件传输协议 FTP、超文本传输协议 HTTP、远程登录 Telnet 、HTTPS以及 POP、SMTP 等邮件传输的协议。
UDP
UDP 是一个无连接非可靠的传输层协议。它在 IP 之上仅提供两个附加服务:多路复用和对数据的错误检查。UDP 在传送数据之前不需要建立连接,远程主机的传输层收到 UDP 报文之后,不需要给出任何确认。由于 UDP 比较简单,因此执行速度比较快、实时性好。UDP 适用于对实时性要求比较高,但对可靠性要求不高的场景,如视频传输、实时通信等。使用 UDP 的应用主要包括小文件传输协议 TFTP、DNS、SMTP、实时传输协议 RTP。
TCP 协议与 UDP 协议的区别
- TCP 是面向连接的,UDP 是无连接的。
- TCP 提供可靠的服务,即通过 TCP 发送的报文保证无差错、不丢失、不重复,并且是按序到达的;TCP 通过校验和、序号确认号、超时重传、确认应答、滑动窗口等机制保证可靠传输。而 UDP 尽最大努力交付,不保证可靠性。
- TCP 由于复杂的机制,因此实时性、工作效率低,但是 UDP 机制简单,因此它的实时性、工作效率更高。
- TCP 只能用于一对一的通信,而 UDP 可用于一对一、一对多、多对一、多对多等传输场景。
- TCP 对系统资源要求比较多(系统为其连接管理、可靠传输所分配的资源),而 UDP 相对来说占用系统资源少。
- TCP 分组首部的开销比 UDP 要大,TCP 有 20 字节的首部开销,而 UDP 只有 8 字节的首部开销。
无连接服务与面向连接服务的区别
- 面向连接服务就是在通信双方进行通信之前,必须先建立连接,在通信过程中,整个连接的情况一直被实时的监控和管理。通信结束后,应该释放这个连接。
- 无连接服务是指两个实体之间的通信不需要事先建立好连接,需要通信时,直接将信息发送到“网络”中,让该信息的传递在网络上尽力而为的往目的地传送。
字节流服务与数据报服务的区别
- 基于流的数据没有边界长度的限制,它源源不断地从通信的一端流入另一端,发送端可以逐个字节地向数据流中写入数据,接收端也可以逐个字节地将它们读出。
- 数据报服务是相对基于流的服务而言的。每个数据报都有一个长度,接收端必须以该长度为最小单位将其所有内容一次性读出,否则数据将被截断并丢弃。
TCP 首部大小、字段的具体含义
- TCP 传送的数据单元称为报文段。一个 TCP 报文段分为 TCP 首部和 TCP 数据两部分,整个 TCP 段作为 IP 数据报的数据部分封装在 IP 数据报中。
- 其首部的前 20 字节是固定的,TCP 报文段既可以用来运载数据,也可以用来建立连接、释放连接和应答。
- TCP 的首部有源端口、目的端口、序号、确认号、数据偏移、保留位、标志、窗口、校验和、紧急指针、选项字段和填充位等。
- 数据偏移:数据部分距离首部的偏移。
- 标志位:URG、ACK、PSH、RST、SYN、FIN。
- 窗口字段是在接收方的通告窗口,是指现在允许对方发送的数据量,接收方的数据缓存空间是有限的,故用窗口值作为接收方让发送方设置其发送窗口的依据,单位是字节。
- 校验和的检验范围包括首部和数据两部分。
- 选项字段 TCP 最初只规定了一种选项,即最大报文段长度 MSS,MSS 是 TCP 报文段中的数据字段的最大长度。
连接过程中需要协商什么,系统需要给 TCP 连接双方分配什么资源
-
TCP 连接都有三个阶段:连接建立、数据传送、连接释放。
-
在连接建立的过程中,解决以下三个问题:
- 要使每一方都能够确切的感受到对方的存在
- 要允许双方协商一些参数:最大窗口值、是否使用窗口扩大选项、时间戳选项及服务质量等
- 能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配
-
TCP 发送缓冲区、接收缓冲区中的内容
- TCP 的发送缓冲区存储的是已发送但是还没有收到确认的报文段、TCP 准备发送的报文段。
- TCP 的接收缓冲区存储的是还没有被应用进程读取的报文段、收到的乱序报文段。
TIME_WAIT 状态何时出现、存在的原因、为什么要等于 2MSL 的时间
- TIME_WAIT 状态是主动关闭的一方收到了对方发来的 FIN 报文并且本端发送了 ACK 报文后的状态。
- MSL 是报文段的最大生存时间,TCP 允许不同的实现可以设置不同的 MSL 值。
- 保证客户端发送的最后一个 ACK 报文能够到达服务器,因为这个 ACK 报文可能丢失,站在服务器的角度看来,服务器已经发送了 FIN 报文请求断开了,客户端还没有给回应,应该是服务器发送的请求断开报文没有收到,于是服务器又会重新发送一次ACK,而客户端就能在这个 2MSL 时间段内收到这个重传的报文,接着给出回应报文,并且会重启 2MSL 计时器。
- 防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个 2MSL 时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。
如何解决系统中存在大量的 TIME_WAIT 状态的问题
- 发现系统存在大量 TIME_WAIT 状态的连接,可以通过调整内核参数解决。
- /etc/sysctl.conf
- net.ipv4.tcp_tw_reuse = 1 // 允许将TIME-WAIT sockets 重新用于新的TCP连接
- net.ipv4.tcp_tw_recycle = 1 // 表示开启TCP连接中TIME-WAIT sockets的快速回收
- net.ipv4.tcp_fin_timeout = 30 // 修改系統默认的 TIMEOUT 时间
TCP 的粘包、拆包问题的原因和解决方案
-
TCP 的数据传输是基于字节流的,虽然应用层和 TCP 传输层之间的数据交互是大小不等的数据块,但是 TCP 把这些数据块视为一连串无结构的字节流,没有边界,另外我们从 TCP 的头部可已看出,没有标识数据长度的字段,因此 TCP 会产生粘包和拆包的现象。
-
原因
- 要发送的数据大于 TCP 发送缓冲区的大小,将会发生拆包。
- 待发送的数据大于 MSS(最大报文长度),TCP 将在传输前进行拆包。
- 要写入 TCP 缓冲区的数据小于缓冲区大小,多次写入缓冲区的数据被一次发送出去,将会发生粘包。
- 接收数据端的应用层没有及时的读取接收缓冲区中的数据,将发生粘包。
-
解决方案:
- 发送端为每个数据报添加包首部,至少包含数据的长度和数据偏移。
- 发送端设置发送数据报的固定的长度(不够可用 0 填充),接收端在接收缓冲区读取固定长度的数据就可以自然地实现把每个数据报拆分开来。
- 在数据报边界之间设置特殊符号,这样接收端就可以根据符号进行分割。
TCP 的可靠传输实现:序号、确认号、超时重传、应答确认、流量控制、拥塞机制
-
TCP 的任务是在 IP 层不可靠的、尽力而为的服务的基础上建立一种可靠数据传输服务。
-
TCP 提供的可靠数据传输服务保证接收方进程从缓冲区读出的字节流与发送方发出的字节流完全一致。
-
TCP 首部的序号字段来保证数据能够有序的交付给应用层,TCP 把数据视为一个无结构但有序的字节流,序号建立在传送的字节流上而不是报文段上。
-
TCP 首部的确认号是期望收到对方的下一个报文段的数据的第一个字节的序号,TCP 的发送方缓冲区会继续存储那些已发送但是还没有收到确认的报文段,以便在需要时重传。
-
TCP 默认使用的是累计确认,即只确认数据流中至第一个丢失字节为止的字节。
-
有两种事件会导致 TCP 的重传:超时和冗余 ACK。
- TCP 每发送一个报文段,就对这个报文段设置一次超时重传计时器,计时器设置的重传时间到期还未收到确认时,就要重传这一报文段。
- 冗余 ACK 即冗余确认,超时触发重传存在一个问题是超时周期往往太长,但是 TCP 提供了冗余 ACK 机制,就是发送方通常在超时事件发生之前,它能够通过冗余 ACK 来较好的检测丢包情况。TCP 规定如果收到了比期望值大的失序报文段时,就发送一个冗余 ACK,指明下一个期待字节的序号。TCP 规定如果发送方收到了对同一个报文段的 3 个冗余 ACK 时,就可以认为之后的报文段已经丢失,就会重传对方所期望的报文段,即快速重传。
-
流量控制:滑动窗口协议、选择确认机制
- TCP 提供流量控制服务来消除发送方使接收方缓存区溢出的可能性,因此可以说流量控制是一个速度匹配服务(匹配发送方与接收方的读取速率)。
- TCP 提供一种基于滑动窗口协议的流量控制机制。滑动窗口使用协议包括停止—等待协议、后退 N 帧协议、选择重传协议。
- 在通信过程中,接收方根据自己的接收缓存大小,动态的调整发送方的发送窗口大小,这称为接收窗口,即调整 TCP 报文段首部的“窗口字段值”,来限制发送方向网络注入报文的速率,同时,发送方会根据当前网络的拥塞程度而确定窗口值,称为拥塞窗口,其大小与网络的带宽和时延密切相关。发送方的发送窗口实际大小取拥塞窗口和接收窗口的最小值。
-
拥塞控制:慢启动、拥塞避免、快速重传和快速恢复
- 拥塞控制是指防止过多的数据注入到网络,使得网络中的路由器或者链路不至于过载。出现拥塞控制时,端点并不了解到拥塞发生的细节,对通信端点来说,拥塞往往表现为通信时延的增加。
- 慢启动
在 TCP 刚刚连接好并开始发送 TCP 报文段时,令拥塞窗口 cwnd=1,即一个最大报文段长度 MSS。每收到一个对新报文段的确认后,将 cwnd 加 1,即增大一个 MSS。使用慢开始算法后,每经过一个往返时延 RTT,拥塞窗口 cwnd 就会加倍,即 cwnd 的大小指数级增长,当拥塞窗口增长到一个规定的慢启动门限时,然后改用拥塞避免算法。 - 拥塞避免
拥塞避免算法是在发送端的拥塞窗口 cwnd 每经过一个往返时延 RTT 就增加一个 MSS 的大小,而不是加倍,使拥塞窗口按照线性规律缓慢增长(即加法增大),而当出现一次超时(网络拥塞)时,令慢启动门限等于当前拥塞窗口 cwnd 的一半(即乘法减小)。乘法减小就是在网络出现拥塞时,无论是在慢启动还是在拥塞避免阶段,只要发送方检测到超时事件的发生(未按时收到确认、重传计时器超时),就把慢启动门限设置为出现拥塞时发送方的拥塞窗口值 cwnd 的一半(不能小于 2),然后把拥塞窗口 cwnd 的值重新设置为 1,执行慢启动。这样做的目的是迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够的时间把队列中积压的分组发送完。
-
快重传和快恢复算法是对慢开始和拥塞避免算法的改进。
-
快速重传
使用了冗余 ACK 来检测丢包的发生,同样冗余 ACK 也用于网络拥塞的检测。快速重传并非取消超时重传计时器,而是在某些情况下可以更早地重传丢失的报文段。当发送方连续收到冗余 ACK 报文时,直接重传对方尚未收到的报文段,而不必等待那个报文段设置的重传计时器超时。 -
快速恢复
发送端收到连续三个冗余 ACK 时,执行“乘法减小”算法,把慢开始门限设置为拥塞时发送方拥塞窗口 cwnd 的一半,然后把拥塞窗口的值设置为慢开始门限 ssthresh 改变后的数值,然后执行拥塞避免算法,使拥塞窗口缓慢地线性增大。由于跳过了 cwnd 从 1 开始慢启动过程,因此被称为快速恢复。 -
在流量控制中,发送方发送数据的量由接收方决定,而在拥塞控制中,则由发送方自己通过检查网络状况来决定。实际上,慢启动、拥塞避免、快重传和快恢复几乎是同时应用在拥塞控制机制中的,在发送方检测到超时的时候,就采用慢开始和拥塞避免,当发送方接收到冗余 ACK 时,就采用快重传和快恢复。
TCP 流量控制与拥塞控制的区别
- 拥塞控制是让网络能够承受现有的网络负荷,是一个全局的过程,涉及所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素。
- 流量控制往往是指点对点的通信量的控制,即接收端控制发送端,它所要做的是抑制发送端发送数据的速率,以便接收端来得及接收。
TCP 接收方窗口与发送方窗口的变化由谁来控制
- 接收方的接收窗口主要是接收方根据自己的接收缓存的大小自行确定,在 TCP 报文首部的窗口字段告知对方。
- 发送方发送窗口的实际大小由流量控制和拥塞控制共同决定,由接收方的接收窗口 rwnd 和发送方的拥塞窗口 cwnd 中较小的那一个确定的。
TCP 的 Nagle 算法
-
TCP/IP 协议中,无论发送多少数据,总是要在数据前面加上协议的首部字段。同时,对方接收到数据,也需要发送 ACK 表示确认。为了尽可能的利用网络带宽,TCP 总是希望尽可能的发送足够大的数据。(一个连接会设置 MSS 参数,因此,TCP/IP 希望每次都能够以 MSS 为数据块的大小来发送数据)。Nagle 算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。(减少大量小包的发送)
-
Nagle 算法就是避免发送小的数据包,要求一个 TCP 连接上最多只能有一个未被确认的小分组。在该分组的确认 ACK 到达之前不能发送其他的小分组,TCP 会在这个时间段收集并暂存待发数据,等待确认到来后,使用一个分组将待发数据发送出去。
如何快速的判断网络拥塞已经发生
观察网络的吞吐量与网络负载的关系
- 如果随着网络负载的增加,网络的吞吐量明显小于正常的吞吐量,那么网络就有可能进入“轻度拥塞”的状态
- 如果吞吐量随着网络负载的增大而快速下降,那么网络就可能已经进入拥塞状态
- 如果网络的负载继续增大,而网络的吞吐量下降到零,那么网络就可能已经进入重度拥塞状态。
UDP 协议的首部长度,字段含义
- UDP 数据报包括 UDP 首部和用户数据,整个 UDP 数据报作为 IP 数据报的数据部分封装在 IP 数据报当中,UDP 首部有 8 字节,4 个字段组成。
- 源端口与目的端口
- 长度:指的是 UDP 数据报的长度,包括首部和数据
- 校验和:检查 UDP 数据报在传输过程中是否有错,有错就丢弃。该字段是可选的。使用的是二进制反码运算求和再取反。
特点
- 无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接;
- 不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层返回任何错误信息;
- 面向数据报: 不能够灵活的控制读写数据的次数和数量
面向数据报
- 应用层交给UDP多长的报文, UDP原样发送, 既不会拆分, 也不会合并;
- 用UDP传输100个字节的数据:如果发送端调用一次sendto, 发送100个字节, 那么接收端也必须调用对应的一次recvfrom, 接收100个字节; 而不能循环调用10次recvfrom, 每次接收10个字节;
UDP的缓冲区
- UDP没有真正意义上的发送缓冲区.
调用sendto会直接交给内核, 由内核将数据传给网络层协议进行后续的传输动作;UDP具有接收缓冲区. 但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致; 如果缓冲区满了, 再到达的UDP数据就会被丢弃;UDP的socket既能读, 也能写, 这个概念叫做全双工
UDP使用注意事项
- UDP协议首部中有一个16位的最大长度. 也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部). 然而64K在当今的互联网环境下, 是一个非常小的数字. 如果我们需要传输的数据超过64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装;
UDP 为什么不可靠,如何实现可靠
- UDP 的实现非常的简单,对于发送方 UDP,它对应用层交付下来的报文,在添加首部后就向下交付给 IP 层,既不合并也不拆分;接收方 UDP 对 IP 层交上来的报文,在去除首部后就原封不动的交给上层应用进程,一次交付一个完整的报文。因此报文不可分割,是 UDP 数据报处理的最小单位。
- UDP 提供尽最大努力的交付,不保证可靠交付,但这并不意味着应用对数据的要求是不可靠的,因此所有维护传输可靠性的工作需要用户在应用层来完成。应用实体可以根据应用的需求来灵活设计自己的可靠性机制。
- 简单的设计如下:
- 添加 seq/ack 机制,确保数据发送到对端。
- 添加发送和接收缓冲区,主要是用户超时重传。
- 添加超时重传机制。
既然 TCP 是可靠的,为什么要有 UDP,存在的意义是什么
- UDP 由于无连接、无重传确认,所以传输效率高、延时小,适合实时性要求高的应用,如游戏服务器,音频,视频等;
- 由于不用维持大的并发量,所以适合巨量服务的 Server,加上合适的时间控制,可以用来设计更大的并发服务器;
- UDP 可以更高效的利用网络带宽,因为如果客户请求频繁,TCP 会在连接建立和关闭上浪费大量的时间和带宽。
Socket 的 tcp 与 udp 编程流程
基于 TCP 的 socket 服务端程序:
创建套接字(socket)
将套接字绑定到一个本地地址和端口上(bind)
将套接字设置为监听模式,准备接收客户端请求(listen)
等待客户端请求到来,当请求到来后,接收连接请求,返回一个新的对应于此次连接的套接字(accept)
用返回的套接字和客户端进行通信(send/recv)
返回等待另一客户端的请求
关闭套接字(close)
基于 TCP 的 socket 客户端程序:
创建套接字(socket)
向服务器发出连接请求(connect)
和服务器进行通信(send/recv)
关闭套接字(close)
基于 UDP 的 socket 服务器端程序:
创建套接字(socket)
将套接字绑定到一个本地地址和端口上(bind)
等待接收数据(recvfrom)
处理请求后给客户端返回数据(sendto)
关闭套接字(close)
基于 UDP 的 socket 客户端程序:
创建套接字(socket)
向服务器发送数据(sendto)
接收来自服务器的数据(recvfrom)
关闭套接字(close)
应用层使用 TCP 的协议有哪些,使用 UDP 的协议有哪些
运行于 TCP 协议之上的协议:
- HTTP 协议:超文本传输协议,用于普通浏览
- HTTPS 协议:安全超文本传输协议,身披 SSL 外衣的 HTTP 协议
- FTP 协议:文件传输协议,用于文件传输
- POP3 协议:邮局协议,收邮件使用
- SMTP 协议:简单邮件传输协议,用来发送电子邮件
- Telent 协议:远程登陆协议,通过一个终端登陆到网络
- SSH 协议:安全外壳协议,用于加密安全登陆,替代安全性差的 Telent 协议
运行于 UDP 协议之上的协议:
- DHCP 协议:动态主机配置协议,动态配置 IP 地址。
- NTP 协议:网络时间协议,用于网络时间同步。
- TFTP 协议:简单文件传输协议,TCP/IP 协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。端口号为 69。
- SNMP 协议:简单网络管理协议。
- NFS: 网络文件系统
- BOOTP: 启动协议(用于无盘设备启动)
- DNS: 域名解析协议
- 自己写UDP程序时自定义的应用层协议