目录
Tcp协议报头:
4位首部长度:
源端口号和目的端口号
32位序号和确认序号
标记位
超时重传机制:
两个问题
连接管理机制
三次握手,四次挥手
建立连接,为什么要有三次握手?
先科普一个概念:SYN洪水:参考博客:[黑客入门] TCP SYN洪水 (SYN Flood) 攻击原理与实现(非常详细)零基础入门到精通,收藏这一篇就够了_tcp syn flood-CSDN博客
正面回答为什么要有三次握手:
Tcp协议报头:
4位首部长度:
首先我们来理解其中最好理解的4位首部长度:
- 在Tcp协议报头中描述报头长度的长度单位是4字节,总范围为[0,60],单位:字节,也就是说,如果Tcp协议的报头长度为36时,设首部长度 = x,则可以推导出x=9,转换为二进制:1001
done
---------------------------------------------------------------------------------------------------------------------------------
源端口号和目的端口号
可以看看这篇文章:Linux网络基础-----传输层UDP协议-CSDN博客
此处不再赘述;
done
---------------------------------------------------------------------------------------------------------------------------------
32位序号和确认序号
- 发送方每次发送的请求中,Tcp报头都会携带对应的32位序号,用来表示当前发送的信息的唯一性,同样的,接收方每次做出应答时,应答的Tcp报头中的32位确认序号就是32位序号 + 1,表示当前确认序号之前的数据已经全部收到!
比如说如果确认序号是3001,那么表示3001之前的所有序号的数据都被收到了!
--------------------------------------------------------------------------------------------------------------------------------
标记位
六位
如果应答确认报文:对于Tcp报头,将标记位ACK置为1,序号和确认序号正常比对,即可表示确认报文。
- 假设发送方先发送了序号为1至1000的数据,接收方成功接收后,会返回一个ACK响应。此时,ACK中携带的确认序号将是1001,表示接收方已经接收到序号为1001之前(即1至1000)的所有数据,并要求发送方从序号1001开始发送下一条数据。
- 需要注意的是,确认应答的起始序号(即确认序号)并不是固定的1001,而是根据每次发送数据的序列号动态变化的。
----------------------------------------------------------------------------------------------------------------------------
超时重传机制:
- 主机 A 发送数据给 B 之后, 可能因为网络拥堵等一系列原因, 数据无法到达主机 B;
- 如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答, 就会进行重发;
即:假设主机A发了数据给主机B,主机B确实收到了,但是主机B发给主机A的ACK应答,主机A没有收到,在经过一段特定的时间后,主机A会将上一次发送给主机B的数据视为丢包了,会重新再传输一次,直到收到来自主机B的ACK应答再开始下一次新的数据发送。
两个问题
到这里,问题有2个,首先,此时主机B会存在2份一摸一样的数据,主机B是如何对这2份数据去重的呢?答案是:ACK序列号!ACK应答中携带确认序号,告诉接收方“我”收到了多少个字节的数据,通过序列号去重相同的数据字节下标,即可解决数据重复的问题!
第二个问题,特定的时间只多久?是否固定?这个问题也很好解释,首先,重传的时间肯定是和数据传输时的网络状态强相关的,那么这个特定的时间一定是随着网络状态动态变化的,在Linux中中,这个特定的时间初始值为500ms,每丢包一次,这个时间就double一次,直到不再丢包。
----------------------------------------------------------------------------------------------------------------------------
连接管理机制
三次握手,四次挥手
三次握手建立连接,四次挥手断开连接;
先说三次握手,上图:
当Client发起Tcp连接时,会将Tcp报头的标记位的SYN置为1,表示这是一次连接请求,Server收到后,会有一次应答,应答的Tcp报头的标记位的SYN和ACK都置为1,Client收到ACK应答后,自身状态会设置为已连接状态,发送一个ACK应答给Server,Server收到这次ACK之后才会将自己的accept返回,成功建立连接。
那么此处又有问题了:Client最后发送的ACK应答,如果Server没收到这次ACK应答怎么办?
此时,Tcp报头中的标记为又要上场了,RST标记位:Client自身建立好Tcp连接时,如果继续发送消息到Server,但是Server并没有收到Client最后一次的ACK响应,此时,Server会向Client应答一次,这次应答的Tcp报头的标记位中的RST标记位和ACK被置为1,Client收到Server的这次应答后,就知道之前的Tcp连接建立失败了,此时Client会释放异常的连接,重新发起三次握手建立连接
四次挥手:
如果Client的数据全部发送完毕了,在应用层使用了close(fd)释放了文件描述符后,向Server发送断开连接的请求,Tcp报头中的FIN标记位置为1,直到Client收到来自Server的ACK应答之后,Client单方面关闭连接成功,不再给Server发送用户的数据。
如果,Client断开连接后,Server还在处理Client之前发送的历史数据时,依然可以给对应Client发送应答,Client也必须针对这些应答再给Server发送ACK响应(空报文)!
问题又来了,应用层调用close之后,文件读写端不是都会被关闭吗?那么Client该如何拿到Server对历史数据的处理结果呢?
很简单,Linux的shutdown接口,函数原型:
可以对指定的文件描述符,进行指定端的关闭操作,SHUT_RD表示只关闭读端,SHUT_WR表示只关闭写端。这样,Client就能拿到Server的数据了;
建立连接,为什么要有三次握手?
要正面回答这个问题,首先要阐述一下为什么一次,二次握手不行‘;
先科普一个概念:SYN洪水:参考博客:[黑客入门] TCP SYN洪水 (SYN Flood) 攻击原理与实现(非常详细)零基础入门到精通,收藏这一篇就够了_tcp syn flood-CSDN博客
对于一次握手,二次握手,由于连接比较简单,Clinet可以伪造大量的SYN连接请求,向服务器发起连接请求,一次握手的话,server极有可能会在短时间内被打满相当多的Tcp链接,因为在Server看来,如果只有一次握手,当收到Client的SYN请求时,就默认双方都建立好了Tcp链接
容易让服务器出现严重的问题,甚至挂掉,二次握手同理,Client可以忽略来自Server的应答,继续SYN洪水,还是容易造成上述一次握手的问题。,但是对于三次握手,服务器虽然无法保证能防御SYN洪水,但是比一次,二次握手好一点,至少能保证Clinet一定在自己建立连接成功之前先建立连接成功的状态!
正面回答为什么要有三次握手:
首先,
- 验证全双工:验证网络的连通性,对于客户端来说,只使用最少的次数验证了双方的连通性,因为能收到服务器的ACK应答;对于服务器来说,也只用了最少的次数验证了双方的连通性,因为同理能收到来自客户端的ACK应答
- 建立双方通信的共识意愿,客户端先发出SYN连接请求,服务器收到了,返回一个ACK应答,至此,客户端建立连接结束,但是Tcp连接是全双工的,服务器也要向客户端发送连接请求SYN,得到客户端的ACK应答后,即完成三次握手,而在其中服务器向客户端发送第一次ACK时会捎带SYN,即捎带应答;
----------------------------------------------------------------------------------------------------------------------------
TODO