本文曾经收录到 Github 仓库,该仓库蕴含 计算机根底、Java 根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享 等外围知识点,欢送 star~
Github 地址:https://github.com/Tyson0314/Java-learning
为什么须要 TCP 协定?
IP 层是「不牢靠」的, 它不保障网络包的交付、不保障网络包的按序交付、也不保障网络包中的数据的完整性。
因为 TCP 是一个工作在传输层的牢靠数据传输的服务, 它能确保接收端接管的网络包是无损坏、无距离、非冗余和按序的。
说说 TCP 的三次握手
假如发送端为客户端,接收端为服务端。开始时客户端和服务端的状态都是CLOSED
。
- 第一次握手:客户端向服务端发动建设连贯申请,客户端会随机生成一个起始序列号 x,客户端向服务端发送的字段中蕴含标记位
SYN=1
,序列号seq=x
。第一次握手前客户端的状态为CLOSE
,第一次握手后客户端的状态为SYN-SENT
。此时服务端的状态为LISTEN
。 - 第二次握手:服务端在收到客户端发来的报文后,会随机生成一个服务端的起始序列号 y,而后给客户端回复一段报文,其中包含标记位
SYN=1
,ACK=1
,序列号seq=y
,确认号ack=x+1
。第二次握手前服务端的状态为LISTEN
,第二次握手后服务端的状态为SYN-RCVD
,此时客户端的状态为SYN-SENT
。(其中SYN=1
示意要和客户端建设一个连贯,ACK=1
示意确认序号无效) - 第三次握手:客户端收到服务端发来的报文后,会再向服务端发送报文,其中蕴含标记位
ACK=1
,序列号seq=x+1
,确认号ack=y+1
。第三次握手前客户端的状态为SYN-SENT
,第三次握手后客户端和服务端的状态都为ESTABLISHED
。 此时连贯建设实现。
两次握手能够吗?
之所以须要第三次握手,次要为了 避免已生效的连贯申请报文段 忽然又传输到了服务端,导致产生问题。
- 比方客户端 A 收回连贯申请,可能因为网络阻塞起因,A 没有收到确认报文,于是 A 再重传一次连贯申请。
- 而后连贯胜利,期待数据传输结束后,就开释了连贯。
- 而后 A 收回的第一个连贯申请等到连贯开释当前的某个工夫才达到服务端 B,此时 B 误认为 A 又收回一次新的连贯申请,于是就向 A 收回确认报文段。
- 如果不采纳三次握手,只有 B 收回确认,就建设新的连贯了,此时 A 不会响应 B 的确认且不发送数据,则 B 始终期待 A 发送数据,浪费资源。
说说 TCP 的四次挥手
- A 的利用过程先向其 TCP 收回连贯开释报文段(
FIN=1,seq=u
),并进行再发送数据,被动敞开 TCP 连贯,进入FIN-WAIT-1
(终止期待 1)状态,期待 B 的确认。 - B 收到连贯开释报文段后即收回确认报文段(
ACK=1,ack=u+1,seq=v
),B 进入CLOSE-WAIT
(敞开期待)状态,此时的 TCP 处于半敞开状态,A 到 B 的连贯开释。 - A 收到 B 的确认后,进入
FIN-WAIT-2
(终止期待 2)状态,期待 B 收回的连贯开释报文段。 - B 发送完数据,就会收回连贯开释报文段(
FIN=1,ACK=1,seq=w,ack=u+1
),B 进入LAST-ACK
(最初确认)状态,期待 A 的确认。 - A 收到 B 的连贯开释报文段后,对此收回确认报文段(
ACK=1,seq=u+1,ack=w+1
),A 进入TIME-WAIT
(工夫期待)状态。此时 TCP 未开释掉,须要通过工夫期待计时器设置的工夫2MSL
(最大报文段生存工夫)后,A 才进入CLOSED
状态。B 收到 A 收回的确认报文段后敞开连贯,若没收到 A 收回的确认报文段,B 就会重传连贯开释报文段。
第四次挥手为什么要期待 2MSL?
- 保障 A 发送的最初一个 ACK 报文段可能达到 B 。这个
ACK
报文段有可能失落,B 收不到这个确认报文,就会超时重传连贯开释报文段,而后 A 能够在2MSL
工夫内收到这个重传的连贯开释报文段,接着 A 重传一次确认,重新启动 2MSL 计时器,最初 A 和 B 都进入到CLOSED
状态,若 A 在TIME-WAIT
状态不期待一段时间,而是发送完 ACK 报文段后立刻开释连贯,则无奈收到 B 重传的连贯开释报文段,所以不会再发送一次确认报文段,B 就无奈失常进入到CLOSED
状态。 - 避免已生效的连贯申请报文段呈现在本连贯中 。A 在发送完最初一个
ACK
报文段后,再通过 2MSL,就能够使这个连贯所产生的所有报文段都从网络中隐没,使下一个新的连贯中不会呈现旧的连贯申请报文段。
为什么是四次挥手?
因为当 Server 端收到 Client 端的 SYN
连贯申请报文后,能够间接发送 SYN+ACK
报文。然而在敞开连贯时,当 Server 端收到 Client 端收回的连贯开释报文时,很可能并不会立刻敞开 SOCKET,所以 Server 端先回复一个 ACK
报文,通知 Client 端我收到你的连贯开释报文了。只有等到 Server 端所有的报文都发送完了,这时 Server 端能力发送连贯开释报文,之后两边才会真正的断开连接。故须要四次挥手。
说说 TCP 报文首部有哪些字段,其作用又别离是什么?
- 16 位端口号:源端口号,主机该报文段是来自哪里;指标端口号,要传给哪个下层协定或应用程序
- 32 位序号:一次 TCP 通信(从 TCP 连贯建设到断开)过程中某一个传输方向上的字节流的每个字节的编号。
- 32 位确认号:用作对另一方发送的 tcp 报文段的响应。其值是收到的 TCP 报文段的序号值加 1。
- 4 位头部长度:示意 tcp 头部有多少个 32bit 字(4 字节)。因为 4 位最大能标识 15,所以 TCP 头部最长是 60 字节。
- 6 位标记位:URG(紧急指针是否无效),ACk(示意确认号是否无效),PSH(缓冲区尚未填满),RST(示意要求对方从新建设连贯),SYN(建设连贯音讯标记接),FIN(示意告知对方本端要敞开连贯了)
- 16 位窗口大小:是 TCP 流量管制的一个伎俩。这里说的窗口,指的是接管通告窗口。它通知对方本端的 TCP 接收缓冲区还能包容多少字节的数据,这样对方就能够管制发送数据的速度。
- 16 位校验和:由发送端填充,接收端对 TCP 报文段执行 CRC 算法以测验 TCP 报文段在传输过程中是否损坏。留神,这个校验不仅包含 TCP 头部,也包含数据局部。这也是 TCP 牢靠传输的一个重要保障。
- 16 位紧急指针:一个正的偏移量。它和序号字段的值相加示意最初一个紧急数据的下一字节的序号。因而,确切地说,这个字段是紧急指针绝对以后序号的偏移,无妨称之为紧急偏移。TCP 的紧急指针是发送端向接收端发送紧急数据的办法。
TCP 有哪些特点?
- TCP 是 面向连贯 的运输层协定。
- 点对点,每一条 TCP 连贯只能有两个端点。
- TCP 提供 牢靠交付 的服务。
- TCP 提供 全双工通信。
- 面向字节流。
TCP 和 UDP 的区别?
- TCP面向连贯;UDP 是无连贯的,即发送数据之前不须要建设连贯。
- TCP 提供 牢靠的服务;UDP 不保障牢靠交付。
- TCP面向字节流,把数据看成一连串无构造的字节流;UDP 是面向报文的。
- TCP 有 拥塞管制;UDP 没有拥塞管制,因而网络呈现拥塞不会使源主机的发送速率升高(对实时利用很有用,如实时视频会议等)。
- 每一条 TCP 连贯只能是 点到点 的;UDP 反对一对一、一对多、多对一和多对多的通信形式。
- TCP 首部开销 20 字节;UDP 的首部开销小,只有 8 个字节。
TCP 和 UDP 别离对应的常见应用层协定有哪些?
基于 TCP 的应用层协定有:HTTP、FTP、SMTP、TELNET、SSH
- HTTP:HyperText Transfer Protocol(超文本传输协定),默认端口 80
- FTP: File Transfer Protocol (文件传输协定), 默认端口(20 用于传输数据,21 用于传输管制信息)
- SMTP: Simple Mail Transfer Protocol (简略邮件传输协定) , 默认端口 25
- TELNET: Teletype over the Network (网络电传), 默认端口 23
- SSH:Secure Shell(平安外壳协定),默认端口 22
基于 UDP 的应用层协定:DNS、TFTP、SNMP
- DNS : Domain Name Service (域名服务), 默认端口 53
- TFTP: Trivial File Transfer Protocol (简略文件传输协定),默认端口 69
- SNMP:Simple Network Management Protocol(简略网络管理协定),通过 UDP 端口 161 接管,只有 Trap 信息采纳 UDP 端口 162。
TCP 的粘包和拆包
TCP 是面向流,没有界线的一串数据。TCP 底层并不理解下层业务数据的具体含意,它会依据 TCP 缓冲区的理论状况进行包的划分,所以在业务上认为,一 个残缺的包可能会被 TCP 拆分成多个包进行发送 , 也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的 TCP 粘包和拆包问题。
为什么会产生粘包和拆包呢?
- 要发送的数据小于 TCP 发送缓冲区的大小,TCP 将屡次写入缓冲区的数据一次发送进来,将会产生粘包;
- 接收数据端的应用层没有及时读取接收缓冲区中的数据,将产生粘包;
- 要发送的数据大于 TCP 发送缓冲区残余空间大小,将会产生拆包;
- 待发送数据大于 MSS(最大报文长度),TCP 在传输前将进行拆包。即 TCP 报文长度 -TCP 头部长度 >MSS。
解决方案:
- 发送端将每个数据包封装为固定长度
- 在数据尾部减少特殊字符进行宰割
- 将数据分为两局部,一部分是头部,一部分是内容体;其中头部构造大小固定,且有一个字段申明内容体的大小。
说说 TCP 是如何确保可靠性的呢?
- 首先,TCP 的连贯是基于 三次握手 ,而断开则是基于 四次挥手。确保连贯和断开的可靠性。
- 其次,TCP 的可靠性,还体现在 有状态;TCP 会记录哪些数据发送了,哪些数据被接管了,哪些没有被承受,并且保障数据包按序达到,保障数据传输不出差错。
- 再次,TCP 的可靠性,还体现在 可管制 。它有数据包校验、ACK 应答、 超时重传(发送方)、失序数据重传(接管方)、抛弃反复数据、流量管制(滑动窗口)和拥塞管制等机制。
说下 TCP 的滑动窗口机制
TCP 利用滑动窗口实现流量管制。流量管制是为了管制发送方发送速率,保障接管方来得及接管。TCP 会话的单方都各自保护一个发送窗口和一个接管窗口。接管窗口大小取决于利用、零碎、硬件的限度。发送窗口则取决于对端通告的接管窗口。接管方发送的确认报文中的 window 字段能够用来管制发送方窗口大小,从而影响发送方的发送速率。将接管方的确认报文 window 字段设置为 0,则发送方不能发送数据。
TCP 头蕴含 window 字段,16bit 位,它代表的是窗口的字节容量,最大为 65535。这个字段是接收端通知发送端本人还有多少缓冲区能够接收数据。于是发送端就能够依据这个接收端的解决能力来发送数据,而不会导致接收端解决不过去。接管窗口的大小是约等于发送窗口的大小。
具体讲一下拥塞管制?
避免过多的数据注入到网络中。几种拥塞管制办法:慢开始 (slow-start)、拥塞防止(congestion avoidance)、快重传(fast retransmit) 和快复原(fast recovery)。
慢开始
把拥塞窗口 cwnd 设置为一个最大报文段 MSS 的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口减少至少一个 MSS 的数值。每通过一个传输轮次,拥塞窗口 cwnd 就加倍。为了避免拥塞窗口 cwnd 增长过大引起网络拥塞,还须要设置一个慢开始门限 ssthresh 状态变量。
当 cwnd < ssthresh 时,应用慢开始算法。
当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞防止算法。
当 cwnd = ssthresh 时,既可应用慢开始算法,也可应用拥塞管制防止算法。
拥塞防止
让拥塞窗口 cwnd 迟缓地增大,每通过一个往返工夫 RTT 就把发送方的拥塞窗口 cwnd 加 1,而不是加倍。这样拥塞窗口 cwnd 按线性法则迟缓增长。
无论在慢开始阶段还是在拥塞防止阶段,只有发送方判断网络呈现拥塞(其依据就是没有收到确认),就要把慢开始门限 ssthresh 设置为呈现拥塞时的发送 方窗口值的一半(但不能小于 2)。而后把拥塞窗口 cwnd 从新设置为 1,执行慢开始算法。这样做的目标就是要迅速缩小主机发送到网络中的分组数,使得产生 拥塞的路由器有足够工夫把队列中积压的分组处理完毕。
快重传
有时个别报文段会在网络中失落,但实际上网络并未产生拥塞。如果发送方迟迟收不到确认,就会产生超时,就会误认为网络产生了拥塞。这就导致发送方谬误地启动慢开始,把拥塞窗口 cwnd 又设置为 1,因此升高了传输效率。
快重传算法能够防止这个问题。快重传算法首先要求接管方每收到一个失序的报文段后就立刻收回反复确认,使发送方及早晓得有报文段没有达到对方。
发送方只有一连收到三个反复确认就该当立刻重传对方尚未收到的报文段,而不用持续期待重传计时器到期。因为发送方尽早重传未被确认的报文段,因而采纳快重传后能够使整个网络吞吐量进步约 20%。
快复原
当发送方间断收到三个反复确认,就会把慢开始门限 ssthresh 减半,接着把 cwnd 值设置为慢开始门限 ssthresh 减半后的数值,而后开始执行拥塞防止算法,使拥塞窗口迟缓地线性增大。
在采纳快复原算法时,慢开始算法只是在 TCP 连贯建设时和网络呈现超时时才应用。采纳这样的拥塞管制办法使得 TCP 的性能有显著的改良。
什么是 SYN 攻打?
咱们都晓得 TCP 连贯建设是须要三次握手, 假如攻击者短时间伪造不同 IP 地址的 SYN 报文, 服务端每接管到 一个 SYN 报文, 就进入 SYN_RCVD 状态, 但服务端发送进来的 ACK + SYN 报文, 无奈失去未知 IP 主机的 ACK 应答, 长此以往就会占满服务端的 SYN 接管队列(未连贯队列), 使得服务器不能为失常用户服务。
如何惟一确定一个 TCP 连贯呢?
TCP 四元组能够惟一的确定一个连贯, 四元组包含如下: 源地址 源端口 目标地址 目标端口。
源地址和目标地址的字段 (32 位) 是在 IP 头部中, 作用是通过 IP 协定发送报文给对方主机。
源端口和目标端口的字段 (16 位) 是在 TCP 头部中, 作用是通知 TCP 协定应该把报文发给哪个过程。
最初给大家分享一个 Github 仓库,下面有大彬整顿的 300 多本经典的计算机书籍 PDF,包含 C 语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生 等,能够 star 一下,下次找书间接在下面搜寻,仓库继续更新中~
Github 地址:https://github.com/Tyson0314/java-books