1.TCP是什么
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。通俗一点的讲,TCP 就是一个双方通信的一个规范标准(协议)。
2.TCP头部报文
我们在学习 TCP 握手过程之前,首先必须了解 TCP 报文头部的一些标志信息,因为在 TCP 握手的过程中,会使用到这些报文信息
2.1 源端口号就是指本地端口,目的端口就是远程端口。
一个数据包(pocket)被解封装成数据段(segment)后就会涉及到连接上层协议的端口问题。
可以想象发送方很多的窗户,接收方也有很多的窗户,这些窗口都标有不同的端口号,源端口号和目的端口号就分别代表从哪个规定的串口发送到对方接收的窗口。不同的应用程度都有着不同的端口。
扩展:应用程序的端口号和应用程序所在主机的 IP 地址统称为 socket(套接字),IP:端口号, 在互联网上 socket
唯一标识每一个应用程序,源端口+源IP+目的端口+目的IP称为”套接字对“,一对套接字就是一个连接,一个客户端与服务器之间的连接。
2.2序列号
用于 TCP 通信过程中某一传输方向上字节流的每个字节的编号,为了确保数据通信的有序性,避免网络中乱序的问题。接收端根据这个编号进行确认,保证分割的数据段在原始数据包的位置。
每个字段在传送中用序列号来标记自己位置的,而这个字段就是用来完成双方传输中确保字段原始位置是按照传输顺序的。(发送方是数据是怎样一个顺序,到了接受方也要确保是这个顺序)
初始序列号由自己定,而后绪的序列号由对端的 ACK 决定:SN_x = ACK_y (x 的序列号 = y 发给 x 的
ACK),
2.3
确认序列号。确认序列号是接收确认端所期望收到的下一序列号。确认序号应当是上次已成功收到数据字节序号加1,只有当标志位中的 ACK 标志为 1 时该确认序列号的字段才有效。主要用来解决不丢包的问题。
若确认号=N,则表明:到序号N-1为止的所有数据都已正确收到。
就是在数据传输的时候是一段一段的,都是由序列号进行标识的,所以说,接收端每接收一段,之后就想要的下一段的序列号就称为「确认序列号」。
2.4
TCP 首部中有 6 个标志比特,它们中的多个可同时被设置为 1,主要是用于操控 TCP 的状态机的,依次为URG,ACK,PSH,RST,SYN,FIN。
2.4.1 ACK
这个标识可以理解为发送端发送数据到接收端,发送的时候 ACK 为 0,标识接收端还未应答,一旦接收端接收数据之后,就将 ACK 置为 1,发送端接收到之后,就知道了接收端已经接收了数据。
2.4.2 SYN
用来建立 TCP 的连接。SYN 标志位和 ACK 标志位搭配使用,当连接请求的时候,SYN=1,ACK=0连接被响应的时候,SYN=1,ACK=1;这个标志的数据包经常被用来进行端口扫描。扫描者发送一个只有 SYN 的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口。
2.4.3 FIN
送端只剩最后的一段数据了,同时要告诉接收端后边没有数据可以接受了,所以用FIN标识一下,接收端看到这个FIN之后,哦!这是接受的最后的数据,接受完就关闭了
2.5 Window size
称为滑动窗口大小。所说的滑动窗口,用来进行流量控制。
3. 为什么进行 TCP 三次握手?
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误,为了解决“网络中存在延迟的重复分组”的问题。
第一,为了确认双方的接收与发送能力是否正常。第二,指定自己的初始化序列号,为后面的可靠传送做准备。第三,如果是 https 协议的话,三次握手这个过程,还会进行数字证书的验证以及加密密钥的生成到。
我们可以使用一个通俗的例子来说明这个问题。假设你和一个男生相互暗恋,有一天你给他发消息,我喜欢你,这个男生接收到这个消息,他回了一句我也喜欢你,我们在一起吧,你看到这个消息特别开心,于是回复一句 好啊,然后你们就在一起了。
- 1.初始状态:客户端处于closed(关闭) 状态,服务器处于listen(监听) 状态。
(你们相互喜欢,谁都不说)
第一次握手:客户端发送请求报文将SYN = j(1)初始化序列号发送给客户端,发送完之后客户端处于 SYN_Send状态。
你发消息告诉男生:我喜欢你
第二次握手:服务端受到 SYN 请求报文之后,如果同意连接,会以自己的SYN(服务端) = K(0)和ack(1) = SYN(客户端) + 1(ACK = 1)报文作为应答,服务器为SYN_Receive 状态。
(男生接收到消息,并且告诉你,他也喜欢你,一起交往可以吗?)
第三次握手: 客户端接收到服务端的SYN + ACK,然后发送 ack = SYN(服务端) + 1(ACK = 1)确认包作为应答,客户端转为established状态。
(你看到消息,回复一句,好的,然后你们就在一起了)
相处几个月下来,你两觉得彼此不太合适,于是你提出了分手。你发消息告诉男生 我们分手吧,男生回复说 好吧,有缘再见,你回复一句 拜拜,之后你们双方拉黑彼此。然后就各自再见了。
初始化状态:客户端和服务端都在连接状态,接下来开始进行四次分手断开连接操作。
第一次分手:第一次分手无论是发送端还是接收端都可以发起,因为 TCP 是全双工的。
假如客户端发送的数据已经发送完毕,发送FIN = 1 告诉服务端,客户端所有数据已经全发完了,服务端你可以关闭接收了,但是如果你们服务端有数据要发给客户端,客户端照样可以接收的。此时客户端处于FIN = 1等待服务端确认释放连接状态。
(你给男生发消息说 我们分手吧)
第二次分手:服务端接收到客户端的释放请求连接之后,知道客户端没有数据要发给自己了,然后服务端发送ACK = 1告诉客户端受到你发给我的信息,此时服务端处于 CLOSE_WAIT 等待关闭状态。
(男生回复 好吧)
第三次分手:此时服务端向客户端把所有的数据发送完了,然后发送一个FIN = 1,用于告诉客户端,服务端的所有数据发送完毕,客户端你也可以关闭接受数据连接了。此时服务端状态处于LAT_ACK状态,来等待确认客户端是否收到了自己的请求。
(男生继续发消息 有缘再会)
第四次分手:此时如果客户端收到了服务端发送完的信息之后,就发送ACK = 1,告诉服务端,客户端已经收到了你的信息。
(再见)
一些小问题:
1. TCP三次握手哪一阶段容易受到攻击
TCP三次握手在第二阶段容易受到攻击,即syn溢出攻击,如果客户机伪造出大量第一次的sys同步报文,服务端就会依次消耗掉很多资源来保存客户端的信息,并进行确认,实际上确认是会失败的,但失败需要一定的时间,因为服务端会连续多次进行第二次握手确认后才认定失败。那么短时间有大量的sys同步报文涌向服务端,服务端资源可能被耗尽,就可能导致正常的客户端得不到响应而失败。
2. 为什么不是一次、二次握手
防止了服务器端的一直等待而浪费资源。
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。如果此时客户端发送的延迟的握手信息服务器收到,然后服务器进行响应,认为客户端要和它建立连接,此时客户端并没有这个意思,但 server 却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了。
3. 为什么建立连接是三次握手,关闭连接是四次挥手
建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。
参考文章:
https://mp.weixin.qq.com/s/5VXhL0dTFcWNyfQ7-7NBEg
https://blog.csdn.net/qq_41261736/article/details/99754329