三、TCP篇
1. TCP
【1】TCP是什么?有哪些特点?
TCP是面向连接的、可靠的、基于字节流的、具有流量控制、拥塞控制、重传机制的传输层控制协议
特点: 1. TCP是面向连接的传输层控制协议 2. 每一条TCP连接只能有两个端点,是点对点连接 3. TCP提供全双工通信,连接的两端都可以临时存放双向通信的数据 4. TCP提供可靠交付的服务,传送的数据保证无差错、不丢失、不重复、并且按序到达 5. TCP面向字节流,将应用程序交下来的数据仅看成是一串无结构的字节流,写入缓存后根据对方的窗口值和当前网络拥塞的程度来决定一个报文段应该包含多少个字节。
(2)TCP头格式
TCP头部有20字节固定,还有长度可变的选项。
1. 源端口和目的端口:各占2字节 2. 序列号:占4字节。在建⽴连接时由计算机⽣成的随机数作为其初始值。 通过SYN包传给接收端主机,每发送⼀次数据,就「累加」⼀次该「数据字节数」的⼤⼩。⽤来解决⽹络包乱序问题。 3. 确认应答号:占4字节。指下⼀次「期望」收到的数据的序列号。 发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。⽤来解决不丢包的问题。 4. 首部长度:占1字节,记录首部的长度,因为有可选项 5. 保留:占6位,保留为今后使用 6. 六个控制位:占6位 * 紧急URG:当'URG=1'时,表明'紧急指针'字段有效,告诉系统应尽快传送该报文段,配合紧急指针字段使用; * 确认ACK:当'ACK=1'时,表明「确认应答」字段有效,在连接建立后所有传送的报文段都必须把ACK置1; * 推送PSH:当两个应用进程进行交互时通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的相应,此时可以使用推送操作; 紧急`URG`和推送`PSH`之间的区别:`URG=1`时,紧急数据不进入接收缓存,直接交付给应用进程,剩下的数据进入接收缓存;`PSH=1`时,不用等到整个接收缓存填满,而是可以直接交付,但注意这里的交付还是从缓存中交付的; * 复位RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。 * 同步SYN:该位为 1 时,表示希望建⽴连接,并在其「序列号」的字段进⾏序列号初始值的设定。 * 终止FIN:该位为 1 时,表示今后不会再有数据发送,希望断开连接。 当通信结束希望断开连接时,通信双⽅的主机之间就可以相互交换FIN位为1的TCP段 7. 窗口大小:2字节。是指发送本报文段的一方的接收窗口,表明从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量; 8. 校验和:2字节。检验和字段检验的范围包括首部和数据两部分;计算校验和时,需要在TCP报文段前面加上12个字节的伪首部,接收方收到此报文段后,仍要加上这个伪首部来计算校验和; 9. 紧急指针:2字节。仅在`URG=1`时才有意义;值得注意的是,即使窗口为零时也可发送紧急数据; 10. 选项:长度可变,最长可达40个字节。 可以用于存放最大报文段长度MSS,即TCP报文段长度减去TCP首部长度。
(3)TCP的发送缓存和接收缓存分别用于存放什么?
发送缓存用于存放: - 发送应用程序传送给发送方TCP准备发送的数据; 【准备发送的数据】 - 已发送出但尚未收到确认的数据。 【已发送但未收到确认的数据】 接收缓存用于存放: - 按序到达的但尚未被接收应用程序读取的数据; 【按序到达但未读取的数据】 - 未按序到达的数据。 【未按序的数据】
(4)TCP怎么保证可靠的传输?
(1)数据包校验 目的是检测数据在传输过程中的任何变化,若检验出包有错,则丢弃报文段并且不给出响应,这时TCP发送数据端超时后会重发数据。 (2)对失序数据包重排序 既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的达到也可能失序。TCP将对失序数据进行重新排序,然后才交给应用层。 (3)丢弃重复数据 (4)应答机制 当收到来自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送的,通常推迟几分之一秒。 (5)超时重传 当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能即时收到一个确认,将重发这个报文段。 (6)流量控制 TCP连接的每一方都有一个一定的大小的缓冲空间。TCP的接收端只允许发送接收端缓冲区所能接纳的数据量,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。 TCP使用的流量控制协议是可变大小的滑动窗口协议。 //TCP会利用窗口控制来提高传输速度,意思是在一个窗口大小内,不用一定要等到应答才能发送下一段数据,窗口大小就是无需等待确认而可以继续发送数据的最大值。如果不使用窗口控制,每一个没收到确认应答的数据都要重发。 (7)拥塞控制 * 如果把窗口定的很大,发送端连续发送大量的数据,可能会造成网络的拥堵(大家都在用网,你在这狂发,吞吐量就那么大,当然会堵),甚至造成网络的瘫痪。所以TCP在为了防止这种情况而进行了拥塞控制。
(5)为什么需要TCP协议?
因为IP层是不可靠的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据的完整性。
所以需要TCP来实现可靠的传输
(6)如何确定一个TCP连接?
TCP四元组:源地址、源端口、目的地址、目的端口
源地址和⽬的地址的字段(32位)是在IP头部中,作⽤是通过IP协议发送报⽂给对⽅主机。 源端⼝和⽬的端⼝的字段(16位)是在TCP头部中,作⽤是告诉TCP协议应该把报⽂发给哪个进程。
(7)TCP最大连接数?
问:有⼀个IP的服务器监听了⼀个端口,它的TCP的最大连接数是多少? 答:最大TCP连接数 = 客户端的IP数 * 客户端的端口数
(8)什么是粘包、拆包?
问:什么是粘包? TCP是基于字节流的,虽然应用层和TCP传输层之间的数据交互是大小不等的数据块,但是TCP把这些数据块仅仅看成一连串无结构的字节流,没有边界; 从TCP的帧结构也可以看出,在TCP的首部没有表示数据长度的字段。 基于上面两点,在使用 TCP 传输数据时,才有粘包或者拆包现象发生的可能。一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包。 接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出来一块,这种情况即发生了拆包和粘包。拆包和粘包的问题导致接收端在处理的时候会非常困难,因为无法区分一个完整的数据包。
问:TCP粘包怎么产生? 1. 发送方产生粘包 采用 TCP 协议传输数据的客户端与服务器经常是保持一个长连接的状态(一次连接发一次数据不存在粘包),双方在连接不断开的情况下,可以一直传输数据。但当发送的数据包过于的小时,那么 TCP 协议默认的会启用 Nagle 算法,将这些较小的数据包进行合并发送(缓冲区数据发送是一个堆压的过程);这个合并过程就是在发送缓冲区中进行的,也就是说数据发送出来它已经是粘包的状态了。 2. 接收方产生粘包 接收方采用 TCP 协议接收数据时的过程是这样的:数据到接收方,从网络模型的下方传递至传输层,传输层的 TCP 协议处理是将其放置接收缓冲区,然后由应用层来主动获取(C 语言用 recv、read 等函数);这时会出现一个问题,就是我们在程序中调用的读取数据函数不能及时的把缓冲区中的数据拿出来,而下一个数据又到来并有一部分放入的缓冲区末尾,等我们读取数据时就是一个粘包。(放数据的速度 > 应用层拿数据速度)
问:怎么解决拆包和粘包? 分包机制一般有两个通用的解决方法: 1. 特殊字符控制; 2. 在包头首都添加数据包的长度。 如果使用 netty 的话,就有专门的编码器和解码器解决拆包和粘包问题了。 tips:UDP没有粘包问题,但是有丢包和乱序。不完整的包是不会有的,收到的都是完全正确的包。传送的数据单位协议是UDP报文或用户数据报,发送的时候既不合并,也不拆分。
2. UDP
(1)UDP协议的特点?
1. 无连接的传输层协议 2. 支持一对一、一对多、多对多的交互通信 3. 尽最大努力交付,即不保证不可靠的传输 4. 面向报文,将应用程序交下来的数据,既不合并也不拆分,保留报文的边界,添加首部后就向下交付到IP层;因此,应用程序必须选择合适大小的报文。 5. UDP首部开销小,只有8字节。TCP则至少需要20字节。 6. 没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低。
(2)UDP头格式
1. ⽬标和源端⼝:主要是告诉UDP协议应该把报⽂发给哪个进程。 2. 包⻓度:UDP用户数据报长度(UDP首部+数据) 3. 校验和:检测UDP用户数据报在传输中是否有错,有错则丢弃
(3)UDP如何计算校验和
- 在计算检验和时,需要在UDP用户数据报之前增加12个字节的伪首部,不向下传送也不向上递交,仅用于计算校验和; - 在发送方,把全零放入检验和字段,再把伪首部和UDP用户数据报看成是由许多16位字,使用全零补齐字节后,按照二进制反码计算这些16位字的和,将此和的二进制反码写入校验和字段,然后发送; - 在接收方,把伪首部、收到的UDP用户数据报以及可能的补齐字节后,按照二进制反码求这些16位字的和,无差错时其结果应为全1,否则出现差错。
(4)TCP、UDP区别?
1. 连接 TCP面向连接、 UDP无连接 2. 服务对象 TCP是一对一的两点服务 UDP支持一对一、一对多、多对多的交互通信 3. 可靠性 TCP是可靠交付:无差错,不丢失,不重复,按序到达 UDP是尽最大努力交付,不保证可靠交付 4. 拥塞控制、流量控制 TCP有拥塞控制和流量控制保证数据传输的安全性 UDP没有拥塞控制,网络拥塞不会影响源主机的发送效率 5. 首部开销 TCP:20字节 UDP:8字节 6. 传输方式 TCP:基于字节流 UDP:基于数据包 7. 分片不同 TCP 的数据⼤⼩如果⼤于 MSS ⼤⼩,则会在传输层进⾏分⽚,⽬标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了⼀个分⽚,只需要传输丢失的这个分⽚。 UDP 的数据⼤⼩如果⼤于 MTU ⼤⼩,则会在 IP 层进⾏分⽚,⽬标主机收到后,在 IP 层组装完数据,接着 再传给传输层,但是如果中途丢了⼀个分⽚,在实现可靠传输的 UDP 时则就需要᯿传所有的数据包,这样 传输效率⾮常差,所以通常 UDP 的报⽂应该⼩于 MTU。 8. 应用场景 TCP:可靠但传输速度慢,若需保证数据完整性用TCP;常用于FTP文件传输、HTTP/HTTPS UDP:不可靠但传输速度快;常用于视频、音频等多媒体通信;广播通信
问:为什么UDP头部没有首部字段,而TCP有 答:因为TCP有可变长的选项字段,而UDP头部长度是固定的,无需多一个字段去记录UDP的首部长度
问:为什么UDP头部有包长度字段,TCP没有?
(5)TCP、UDP分别对应的常见应用层协议有哪些?
TCP对应的应用层协议: 1. FTP协议:文件传输协议,使用21端口。常说某某计算机打开了FTP服务便是启动了文件传输协议。下载文件、上传主页都要用FTP服务。 2. Telnet:是一种用于远程登录的端口,用户可以以自己的身份远程连接到计算机上,通过这种端口可以提供一种基于DOS模式下的通信服务。如以前的BBS是纯字符界面的,支持BBS的服务器将23端口打开,对外提供服务。 3. SMTP:简单邮件传输协议,现在很多邮件服务器都用此协议用于发送邮件。常见的免费邮件服务器中用的就是这个邮件服务端口,所以在电子邮件设置中常看到有SMTP端口设置这个栏,服务器开放的是25端口。 4. POP3:与SMTP对应,POP3用于接收邮件。通常情况下,POP3协议所用的是110端口。只要你有相应的使用POP3协议的程序(Fo-xmail、Outlook等),就可以不以Web方式登录进邮箱界面,直接用邮件程序就可以收到邮件。 5. HTTP
基于UDP的应用层协议: 1. DNS:用于域名解析服务,将域名地址转换为IP地址。DNS用的是53号端口。 2. SNMP:简单网络管理协议,使用161端口,用来管理网络设备的,由于网络设备很多,无连接的服务就体现出其优势。 3. TFTP:Trival File Transfer Protocol,简单文件传输协议,69端口
3. TCP三次握手
(1)TCP三次握手
1. 一开始,客户端和服务器都处于CLOSE状态。先是服务器主动监听某个端口,处于LISTEN状态 2. 客户端向服务端发出连接请求报文段。 客户端会随机初始化序列号(client_isn),同时把SYN标志置1,表示SYN报文。 接着把该报文发送给服务器,该报文不包含应用层数据,之后客户端处于SYN_SENT状态 3. 服务器接收到客户端的连接请求报文后,如果同意连接, 首先服务器也随机初始化自己的序列号(server_isn), 其次把TCP首部的确认应答号字段填入client_isn+1, 接着把SYN和ACK标志位置1. 最后把报文发给客户端, 该报文也不包含应用层数据,之后服务器处于SYN_RCVD状态。 4. 客户端接收到服务器报文后,还要向服务器回应最后一个应答报文。 首先该应答报文TCP首部ACK标志位置1, 其次确认应答号字段填入server_isn+1, 最后把报文发送给服务器, 这次报文可以携带客户端到服务器的数据,之后客户端处于ESTABLISHED状态。 5. 服务器收到客户端的应答报文后,也进入ESTABLISHED状态。
(2)如何在Linux系统中查看TCP状态
netstat -napt
(3)为什么是三次握手?不是两次、四次
为什么不四次: 1. 三次就行没必要四次;避免资源浪费。
为什么不两次: 回答1、两次不能确认双方的接受能力、发送能力是否正常。 * 第一次握手,服务器得出结论:服务器的接收、客户端的发送没问题 * 第二次握手,客户端得出结论:客户端发送和接收没问题,服务器发送接收没问题。 * 第三次握手,服务器得出结论:客户端发送和接收没问题,服务器发送接收没问题。 回答2、两次握手不能同步双方初始序列号
三次握手是为了防止客户端的请求报文在网络滞留,客户端超时重传了请求报文,服务器建立连接,传输数据,释放连接之后,服务器又收到了客户端滞留的请求报文,建立连接一直等待客户端发送数据。 两次握手的话: 服务器对客户端的请求进行回应(第二次握手后),就会理所当然的认为已建立连接,而如果客户端并没有收到服务器的回应呢?此时,客户端仍认为连接未建立,服务器会对已建立的保存必要的资源。如果大量的这种情况,服务器会奔溃。
三次握手原因有三点: 1. 避免历史连接 2. 同步双方初始序列号 3. 避免资源浪费
序列号的作用:除去重复数据、按序接收,哪些收到哪些没收到
- 接收方可以去除重复的数据
- 接收方可以根据数据包的序列号按序接收
- 可以标识发送出去的数据包中,哪些是已经被对方收到的
之所以需要进行三次握手,也就是客户端最后要发送一次确认报文段,主要是为了防止已失效的连接请求报文段突然传送到了服务端,因而产生错误;所谓“已失效的连接请求报文段”,是指:
- 客户端发送一次连接请求报文段,在某些网络节点长时间滞留而未丢失,于是客户端再发送一次连接请求,成功建立连接后又成功释放连接;
- 此时第一个连接请求终于到达,服务端误认为这是客户端新的连接请求,于是就向客户端发送确认报文段,同意建立连接;
- 此时如果不采用第三次握手,那么只要服务端发出确认请求,新的连接就建立了,但由于客户端实际上并没有发出新的连接请求,自然不会理睬,而服务端一直等待客户端发送数据,造成资源浪费。
(4)为什么客户端和服务器端的初始序列号ISN不相同?
1. 如果⼀个已经失效的连接被重⽤了,但是该旧连接的历史报⽂还残留在⽹络中,如果序列号相同,那么就⽆法分辨出该报⽂是不是历史报⽂,如果历史报⽂被新的连接接收了,则会产⽣数据错乱。 所以,每次建⽴连接前重新初始化⼀个序列号主要是为了通信双⽅能够根据序号将不属于本连接的报⽂段丢弃。 2. 另⼀⽅⾯是为了安全性,防⽌⿊客伪造的相同序列号的TCP报⽂被对⽅接收。
(5)既然IP层会分片,为什么TCP层还需要MSS呢?
MTU:一个网络包的最大长度,以太网中一般为1500字节。
MSS:除去IP和TCP头部后,一个网络包能容纳的TCP数据的最大长度
如果一个IP分片丢失,整个IP报文的所有分片都得重传。所以,为了达到最佳的传输效能TCP协议在建立连接的时候通常要协商双方的MSS值,之后形成的IP包的长度也就不会大于MTU,自然就不用IP分片了。
4. TCP四次挥手
(1)TCP四次挥手
双方都可以通过四次挥手主动断开连接
以客户端主动断开连接为例:
1. 客户端打算关闭连接,此时会发送一个TCP首部FIN标志置1的报文,也即FIN报文,之后客户端进入FIN_WAIT_1状态 2. 服务器收到该报文后,就向客户端发送ACK应答报文,接着客户端进入CLOSED_WAIT状态 3. 客户端收到服务端的ACK应答报文后,进入FIN_WAIT_2状态 4. 等待服务器处理完数据后,也向客户端发送FIN报文,之后服务器进入LAST_ACK状态 5. 客户端收到服务器的FIN报文后,回一个ACK应答报文,之后进入TIME_WAIT状态 6. 服务器收到了ACK应答报文后,就进入了CLOSED状态,至此服务器已经完成了连接的关闭 7. 客户端在经过一段时间后(2MSL),自动进入CLOSED状态,至此客户端也完成了连接的关闭
主动关闭连接的,才有TIME_WAIT状态
(2)为什么挥手需要四次
* 关闭连接时,客户端向服务器发送FIN时,仅仅表示客户端不再发送数据了但是还能接收数据。 * 服务器收到客户端的FIN报文后,先回一个ACK应答报文,而服务器可能还有数据需要处理和发送,等服务器不再发送数据后,才发送FIN报文给 客户端表示同意现在关闭连接。 服务器需要等待完成数据的发送和处理,所以服务器的ACK和FIN一般都会分开发送。
(3)TIME_WAIT是什么?为什么需要?
问:为什么TIME_WAIT必须等待2MSL的时间? 1. 保证最后一次握手报文能到B,能进行超时重传。 2. 2MSL后,这次连接的所有报文都会消失,不会影响下一次连接。 详细解答: 1. 为了保证发送方发送的最后一个ACK报文能够到达接收方,帮助接收方关闭连接。如果这个报文丢失,处于LAST_ACK的接收方就会超时重传FIN报文,接收方在2MSL时间内接收到这个重传报文,接着重传一次ACK确认报文,重新启动2MSL计时器,接收方收到后则关闭连接。 如果A在TIME_WAIT不等待你一段时间,而是发送完ACK后直接释放连接,该报文丢失另一方则不能按照正常步骤进入CLOSED状态。 2. 防止已失效的连接请求报文段出现在本连接中。 A发送完最后一个ACK报文段后,再经过2MSL就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,这样就可以使下一个连接中不会出现这种旧的连接请求报文段。
问:为什么TIME_WAIT等待的时间是2MSL? MSL是Maximum Segment Lifetime,报文最大生存时间。 MSL和TTL的区别是:MSL的单位是时间,TTL是经过路由跳数 MSL >= TTL 网络中可能存在来自接收方的数据包,当这些数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待2倍的时间 2MSL的时间是从客户端接收到FIN后发送ACK开始计时的。如果在TIME_WAIT时间内,因为客户端的ACK没有传输到服务端,客户端又接收到了服务器重发的FIN报文,那么2MSL时间将重新计时。
TIME_WAIT等待时间应合理 * 服务器正常收到四次挥手的最后一个ACK报文,则服务器正常关闭连接 * 服务器没有收到四次挥手的最后一个ACK报文时,则会重发FIN关闭连接报文(重新第三次挥手)等待新的ACK报文。
问:TIME_WAIT过多有什么危害? 1. 第一是内存资源占用 2. 第二是对端口资源的占用,一个TCP连接至少消耗一个本地端口;端口被占满会导致无法创建新的连接。
(4)保活计时器的作用?如果已建立连接,但客户端突出故障怎么办?
TCP有一个机制是保活机制
TCP有一个保活计时器,在这个时间段内,如果没有任何连接相关的活动,TCP保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前TCP连接已经死亡,系统内核将错误信息通知给上层应用程序。 //服务器每次收到一个客户的数据,就重新设置保活计时器,时间的设置通常是两个小时。若两个小时都没有收到客户端的数据,服务器就发送一个探测报文,以后则隔75秒发送一个。若连续发送10个探测报文段后仍然无客户端的响应,服务器就认为客户端出了故障,接着就关闭这个连接。
如果开启了TCP报活,需要考虑以下几种情况:
第⼀种,对端程序是正常⼯作的。当TCP保活的探测报⽂发送给对端, 对端会正常响应,这样TCP保活时间会被重置,等待下⼀个TCP保活时间的到来。 第⼆种,对端程序崩溃并重启。当TCP保活的探测报⽂发送给对端后,对端是可以响应的,但由于没有该连接的有效信息,会产⽣⼀个RST报⽂,这样很快就会发现TCP连接已经被重置。 第三种,是对端程序崩溃,或对端由于其他原因导致报⽂不可达。当TCP保活的探测报⽂发送给对端后,⽯沉⼤海,没有响应,连续⼏次,达到保活探测次数后,TCP会报告该TCP连接已经死亡。