在上一篇网络基础的博客当中,我们对应用层协议--HTTP协议进行了详解,接下来我们对传输层协议进行详解
目录
1.传输层协议
2.UDP协议
2.1协议内容
2.2协议格式
2.3协议特性
3.TCP协议
3.1协议内容
3.2协议格式
3.3协议特性
3.3.1三次握手建立连接
3.3.2四次挥手断开连接
3.3.3稳定连接总结
3.3.4TCP的保活机制
3.3.5可靠传输机制
1.传输层协议
传输层协议是负责客户端和服务端(两端)之间的数据传输协议,常用的知名协议有TCP协议和UDP协议,那么接下来我们将对这两种协议进行详解。
2.UDP协议
2.1协议内容
UDP协议是一种用户数据报传输协议,它是一种无连接、不可靠、且面向数据报传输的协议。
2.2协议格式
UDP协议格式在底层代码设计中是这个样子的:
struct
{
uint16_t uh_sport;//源端端口号
uint16_t uh_dport;//对端端口号
uint16_t uh_ulen;//数据报文长度
uint16_t uh_sum;//校验和
};
四种数据类型都为uint16_t,实际上是short int数据类型,即四种数据各占2字节(16位比特位),共计占据8字节(kb)。
其中,16位的源端端口号和对端端口号描述了是那两端进程在进行通信,16位数据报文长度描述了包含UDP头部在内的数据长度,16为校验和用于校验数据传输的一致性,确保接收到的数据和对方发送的相同(如果数据不一致,则不能交给具体程序处理)。
校验和验证的算法为:二进程反码求和算法。具体过程为:发送方在发送数据时先将校验和字段制0,然后从报头开始逐字节取反相加,高出16为的部分截断再与低16位相加,直到数据末尾。接收方收到校验和之后,也从报头开始逐个取反求和,如果最终得到结果为0则说明收发数据一致。
结合16位数据能描述的最大数字位:65535,所以一份UDP报文包含头部在内,其大小必须小于64k。即当应用层使用sendto发送数据时,数据长度必须小于64-8k,这8k数据为UDP头部的四种数据(2*4k)。
2.3协议特性
UDP协议具有三条特性,这是在之前博客中有提到的内容,它们分别是:无连接(通信中并不需要建立连接,只需知道对方地址便可发送数据);不可靠(传输中不保证数据有序到达对端);面向数据报传输(传输的每条数据存在大小限制64-8k)。
UDP协议的特性会影响我们对于程序的设计,首先UDP协议传输数据大小存在限制,所以我们在使用sento发送数据时,一次性不能发送太多数据,必须在应用层进行分包处理;其次UDP协议并不保证数据安全和有序到达,所以在应用层需进行包序管理,确保数据安全和传输顺序。
(UDP协议支持局域网广播)
3.TCP协议
3.1协议内容
TCP协议是一种传输控制协议,它是一种面向连接、可靠、且面向字节流传输的协议。
3.2协议格式
我们使用vi /usr/include/netinet/tcp.h命令,可以查看TCP在代码中的设计格式如下:
结合TCP结构和代码中描述,我们对其中数据种类进行画图展示:
其中,16位th_sport源端端口和16位th_dport对端端口用于描述通信两端;32位th_seq序号需要用于对传输的每个字节进行排序,接口放会根据接收到的序号来对数据进行排序,确保数据的有序交付;32位th_ack确认序号用于接收方收到数据之后,通过确认序号告知对方多少号之前的序号已被收到。
4位头部长度(头长)是以4字节为单位描述TCP报文头部长度(TCP报头最长60字节,最小20字节),在解析过程中先取出20字节的固定数据,然后根据头长确认取出选项数据。
报头长度并不固定,但其中前20字节内容固定,只有在选项数据中存在0~40字节的不定长度(
6位保留位未被使用,不具有具体的功能;6位标志位有:FIN、SYN、RST、PUSH、ACK和URG,不同的标志代表不同的请求。
16位th_win窗口,用于实现滑动窗口机制,进行流量控制,防止因接收方内存不足而导致数据丢失的情况。
16位th_sum校验和,同UDP协议采用二进制反码求和算法,校验数据收发的一致性。16位th_urp紧急指针,用于指向带外优先数据的结束位置,便于优先数据的控制。
3.3协议特性
对于TCP的协议特性有:面向连接,可靠传输和提供字节流传输服务,我们首先来对特性中的面向连接进行解析,在双方通信之前,需要先建立连接,确保双方在线,且具有数据收发的能力。
具体的连接管理内容为:三次握手建立连接(通信前,先建立连接,确保双发具有数据收发的能力),四次挥手断开连接(通信结束后,存在一个断开连接的过程,避免出现意外)。
3.3.1三次握手建立连接
三次握手建立连接过程示意图如下:
第一次握手客户端将TCP报文中标志位SYN置1,并随机产生一个序号值seq=J(保存在序列号资源当中),指明客户端连接到服务端的端口,然后发送给服务端,发送结束后客户端进入SYN_SENT状态,等待服务端处理请求。
第二次握手服务端收到客户端请求后(SYN=1,明确是客户端发送的连接建立请求),将TCP报文中标志位SYN和ACK都置1,并使ack=J+1,随机产生一个序号值seq=K,然后发送给客户端,发送结束后服务端进入SYN_RCVD状态,等待客户端进一步请求。
第三次握手客户端收到服务端的确认消息之后,检查序列号ack是否为J+1和标志位ACK是否为1,检查无误后将标志位ACK置1,使序列号ack=K+1并发送给服务端;然后服务端再检查ACK是否为1,ack是否为K+1,检查无误则两端连接建立成功,客户端和服务端进入ESTABLISHED状态,三次握手完成。
3.3.2四次挥手断开连接
四次挥手断开连接过程示意图如下:
挥手断开请求可以是客户端也可以是服务端,所以图中我们通过请求的发送方和接受发来说明。
第一次挥手发送方发送FIN标志位,并设置序列号seq,然后发送方进入FIN_WAIT_1状态,表示不再有数据向接收方发送。
第二次挥手接收方收到发送的FIN报文段后,向发送方发送标志位为ACK的报文段,并将序列号ack设置为接收到的seq+1,确认应答结束,然后发送发进入FIN_WAIT_2状态,即接收方确认并同意了请求方的关闭请求。
第三次挥手接收方向发送方发送标志位FIN的报文段,请求断开连接。
第四次挥手发送方收到接收方的FIN报文段后,向接收方发送标志位为ACK的报文段,然后进入TIME_WAIT状态。接收方收到发送方的ACK报文段后就会关闭连接,此时发送方等待2MSL(2分钟)没收到回复,则说明接收方已经正常关闭,之后发送方也关闭连接。
3.3.3稳定连接总结
第一个方面是:建立连接时为什么是三次握手。我们建立连接的初衷是双方都具有数据收发的能力,因此双方都需要向对方发送SYN请求,其次服务端收到客户端发送SYN请求时,可以直接发送SYN+ACK报文(SYN用于同步,ACK用于应答),所以建立连接只需要三次握手。
如果两次握手的话,可能SYN延迟到达,与重发的SYN冲突;也可能受到客户端发送完SYN请求后直接退出的恶意攻击。如此四次握手的话,是没有必要的,因为服务端回应时可以直接发送SYN+ACK报文。
第二个方面是:断开连接为什么是四次挥手。断开连接时主动关闭方先发送FIN报文告知对方自己不再发送数据,接收关闭方做出ACK应答。此时接受关闭放仍可能存在数据向主动关闭方发送(缓冲区),所以接受关闭方需等待上层数据发送结束后,才向对方发送FIN报文告知数据发送截至。最后再有主动关闭放发送ACK报文确认应答。
这也是由于TCP协议的全双工模式:两端都具有独立的数据收发能力,所以在连接关闭时,需等待双方数据发送结束。因此,四次挥手断开连接未被合并成为三次。
第三个方面是:为什么需要主动关闭方要等待的时间是2MSL。首先如果因为网络等问题导致,被动关闭方并未收到主动关闭方的ACK报文。那么若是主动关闭方立即关闭,而不等待的话,会导致超时后无法重传FIN报文给对端,导致TCP的全双工通信并未可靠关闭。
其次如果主动关闭方发送最后的ACK请求后立即关闭,然后其再向对方发送了连接建立请求,则无法保证新建立连接的端口和之前连接端口不同,也就意味着新旧端口可能一致。这就导致若之前存在数据滞留的情况,这些滞留的数据便会顺着相同端口的新连接被传输,导致数据收发混乱。所以TCP连接需要在TIME_WAIT状态等待2MSL,才能保证本次连接的数据全部消失在网络中。
3.3.4TCP的保活机制
在TCP通信当中,如果客户端和服务端通信频率不高,通信中突然网络断开,双方没有四次挥手断开连接的机会。那么因为二者通信频率较低,可能连接断开的频率需要很久才会被发现,不存在的通信较长时间的占用资源很明显是我们不期待看到的。
所以我们引入TCP的保活机制,当客户端和服务端长时间未进行通信时,则TCP服务器会自动向客户端发送保活探测包,要求得到对方响应,若多次请求为得到响应,则认为连接断开。在ipv4标准中,默认为若两端7200s未进行通信,则每隔75s向客户端发送保活探测包,9次未得响应的话,则认为连接断开。(以上时间均可配置,可用套接字选项进行设置)
3.3.5可靠传输机制
TCP协议的可靠传输机制是通过一些特殊机制来实现的:
- 面向连接--确保双方都具有数据收发能力;
- 丢包检测机制--确认应答机制:接收方要针对收到的每一条数据进行回复;
- 丢包重传机制--超时重传机制:等待确认回复超时则重传数据;
- 序号字段--进行包序管理,有序交付数据;
- 校验和字段--校验数据一致性,不一致则重传。