「前言」文章内容大致是传输层协议,TCP协议讲解,续上篇UDP协议。
「归属专栏」网络编程
「主页链接」个人主页
「笔者」枫叶先生(fy)
TCP(
Transmission Control Protoco
l)是一种面向连接的、可靠的传输协议,TCP全称为
"传输控制协议”,TCP人如其名,要对数据的传输进行一个详细的控制。
报头下来就是数据,即上层扔下来的数据,数据包括上层协议报头+数据,这个也不谈。
TCP如何将报头与有效载荷进行分离?即如何解包
TCP从下层获取到一个TCP报文后,虽然TCP不知道报头的具体长度,但报文的前20个字节是TCP的基本报头,并且这20字节当中涵盖了4位的首部长度。
TCP解包的过程如下:
0000 ~ 1111
,即最大长度是15,又因为4位首部长度的基本单位是4字节,所以15*4=60
字节[20 ~ 60]
注意:不同的协议层对数据包有不同的称谓,在传输层叫做数据段(segment)
,在网络层叫做数据报 (datagram)
,在链路层叫做数据帧(frame)
TCP如何决定将有效载荷交付给上层的哪一个协议?即如何分用
应用层的每一个网络进程都必须绑定一个端口号。
TCP的报头中涵盖了目的端口号,因此TCP可以提取出报头中的目的端口号,找到对应的应用层进程,进而将有效载荷交给对应的应用层进程进行处理,分用完毕
如何解包与分用已经解决,封装就是逆过来
有一个问题,TCP报头问什么没有有效载荷的大小??
面向字节流和可靠性下面再谈
收到一个报文,是如何找到曾经绑定特定端口号的进程?网络协议栈与文件是什么关系
找到进程了,如何把数据给给进程??
filles_struct
表的指针,该表里面有上层打开的文件对应的文件描述符,通过文件符可以找到该文件,然后就可以找到该文件的缓冲区,然后把数据放入文件缓冲区里面,上层再从该缓冲区里面读取数据如何理解报头?
在上一篇UDP已经谈过,不再赘述
下面开始学习TCP的可靠性
谈可靠性之前就先要谈什么是不可靠
为什么网络传输中,会存在不可靠?
但是如果是网络的话,因为两台主机之间相距太远,数据在经过某些中间设备可能会丢失,信号衰减导致比特位丢失、比特位翻转等等现象,即传输过程干扰因素增多。
出现这种问题仅仅是传输距离变远了
即所有的网络问题本质都是传输距离变远了,即网络传输出现不可靠现象的原因就是传输距离变远了
网络传输不可靠现象有哪些?
下面都是围绕这些问题去解决的
如何传输距离变长了,存不存在绝对的可靠性??
比如有A、B两个人,相距500米进行对话
A:B你吃饭了么?(A不能保证这句话被B收到了)
只有B进行应答,A才能确认他讲的话被B收到了,
但是B不确定自己的话被A收到了,只有A再次应答才能确认
B看到A回复的内容,就已经确认自己的上一句话被A收到了
但是存在一个问题,最新的内容因为没有应答,无法确认对方是否收到
所以,我们认为:
100%
被对方收到了——确认应答了,可靠所以,绝对的可靠性是不存在的,但是存在相对的可靠性,即一个报文只要收到了应答,就可以保证该报文的可靠性
TCP的工作模式有两种
第一种(不是TCP真正的工作模式)
每一个发送的数据段,都要给一个确认应答,收到应答后再发送下一个数据段(串行)。这样做有一个比较大的缺点,就是性能较差
第二种(TCP真正的工作模式)
一次发送多条数据段(并行),对端再进行应答,这样就可以大大的提高性能
第二种情况是TCP的真正工作模式,即主流,但是也会存在第一种工作模式,第一种情况是很少的
无论是客户端发给服务端,还是服务端发给客户端,双方都需要应答,即TCP客户端和服务端双方的地位是对等的
这里只是浅浅提一下,下面才开始讲解,这里是为了方便理解序号和确认序号
TCP将发送出去的每个字节数据都进行了编号,这个编号叫做序列号。
每一个ACK都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据,下一次你从哪里开始发,每次的ack都是上次收到上次数据序列号加1
32位序号
双方在进行网络通信时,允许一方向另一方连续发送多个报文数据,只要保证发送的每个报文都有对应的应答,就能保证这些报文被对方收到了
TCP将发送出去的每个字节数据都进行了编号,这个编号叫做序列号。这个上面已经说过了
需要注意的是,TCP协议对于乱序报文的处理是在传输层完成的,而不需要应用层进行干预。
接收端收到的数据会根据序列号的顺序进行处理和组装,以确保数据的完整性和正确性。这样可以解决数据传输过程中的乱序问题,确保数据按照发送端的顺序传输到应用层进行处理。
32位确认序号
TCP报头当中的32位确认序号是告诉对端,我当前已经收到了哪些数据,你的数据下一次应该从哪里开始发,每一个ACK
都带有对应的确认序列号
根据上面的例子,假设主机B已经成功收到主机A的序列号为1的报文和序列号为1001的报文,则主机B会发送两个ACK确认报文:
1001
,表示已经成功接收了序列号1-1000
的字节数据。2001
,表示已经成功接收了序列号1001-2000
的字节数据。
ack确认应答和确认序号:保证接收方已经收到了ack序号之前所有的报文
传输过程中报文丢失怎么办?
通过序号和确认序号还可以判断某个报文是否丢失,怎么办后序谈
为什么要用两套序号机制?
发送方有一套序号和确认序号,接收方也有一套序号和确认序号,为什么
因为TCP是全双工的,地位对等的,双方可能存在同时想给对方发送消息的情况:
TCP本身是具有接收缓冲区和发送缓冲区的(全双工):
这个在上一篇UDP已经谈论过,不再赘述
窗口大小
为了解决这个问题,TCP的报头中有一个称为窗口大小的字段,它占用了16个比特位。这个窗口大小表示接收端当前接收缓冲区中的剩余空间大小,也即接收端当前能够接收数据的能力
接收端可以通过窗口大小字段告诉发送端自己的接收缓冲区还有多少空间。发送端可以根据这个窗口大小字段来调整发送数据的速度:
注意:自己发送数据就填自己的窗口大小,对端发送数据也是填对端的窗口大小,这样双方就交换了自己缓冲区的接收能力
总之,窗口大小字段在TCP中起到了调控发送端和接收端之间数据传输速度的作用,确保数据传输过程中的流量控制。
六个标志位的作用:
URG(Urgent)
:表示紧急指针字段是否有效。如果设置了这个标志位,那么紧急指针字段的值将被解释为一个偏移量,指示紧急数据的结束位置。ACK(Acknowledgment)
:表示确认序号字段是否有效。如果设置了这个标志位,那么确认序号字段的值将被解释为期望收到的下一个数据的序号。 PSH(Push)
:表示接收端应该尽快将数据交给应用层,而不需要等待缓冲区填满。该标志位通常在发送端需要立即将数据发送给接收端时设置。RST(Reset)
:表示重置连接。当接收端收到一个无法识别的序号或者收到一个不符合当前连接状态的报文时,会发送一个带有RST标志位的报文来重置连接。SYN(Synchronize)
:表示建立连接。在建立TCP连接时,发送端和接收端都会发送一个带有SYN标志位的报文来进行握手。FIN(Finish)
:表示结束连接。当发送端没有数据要发送了,或者接收到FIN报文后已经完成了数据的接收,就会发送一个带有FIN标志位的报文来结束连接这六个标志位全部都是一个比特位,为1则说明该标志位被设置,为0则为假
在开始讲解前,先明确一个:
TCP报文是有类型的!
这些TCP报文该如何区分??
通过设置六个标记为即可完成对TCP报文进行区分
SYN(Synchronize)
:表示建立连接。
三次握手后序详谈
FIN(Finish)
:表示结束连接。
四次挥手后序详谈
ACK(Acknowledgment)
:表示确认序号字段是否有效。
SYN、FIN和ACK这三个后序详谈
PSH(Push)
,PSH被设置为1,表示发送端告诉接收端应该尽快将数据交给应用层
read/recv读取数据问题
总结起来,read/recv函数在读取数据时需要缓冲区中的数据量达到一定量(水位线)才能进行读取,并且PSH标志可以影响数据的交付时机。
URG(Urgent)
:表示紧急指针字段是否有效。
16位紧急指针:标识哪部分数据是紧急数据。
实际上,在现代的TCP协议中,紧急指针的使用已经不常见了,99%的情况下都用不到
recv/send函数就有设置URG的参数
recv函数的第四个参数flags有一个叫做MSG_OOB的选项可供设置,其中OOB是带外数据(out-of-band)的简称,带外数据就是一些比较重要的数据,因此上层如果想读取紧急数据,就可以在使用recv函数进行读取,并设置MSG_OOB选项
与之对应的send函数的第四个参数flags也提供了一个叫做MSG_OOB的选项,上层如果想发送紧急数据,就可以使用send函数进行写入,并设置MSG_OOB选项。
RST(Reset)
:表示重置连接。
在访问某些网站时,会出现以下字样,代表服务端寄了
以上就是TCP的基本报头
在谈论这个话题之前,先谈一个问题:
如何看待TCP的接收缓冲区?
char buffer[N]
,N就是缓冲区的大小,即可以把接收缓冲区看成固定大小的数组,即只要在数据里面的数据(每个字节)天然有了序号TCP的超时重传机制
TCP的超时重传机制是为了确保数据能够可靠地传输而设计的。当发送端发送一个数据段后,会启动一个定时器。如果在定时器超时之前,发送端收到了对应的确认,那么定时器会被取消。如果在定时器超时之后,发送端还没有收到确认,那么就会重新发送该数据段。
TCP的超时重传机制可以分为以下几个步骤:
这个过程会一直重复,直到发送端收到了确认或者达到了最大重传次数。
丢包的两种情况
但是,主机A未收到B发来的确认应答,也可能是因为ACK丢失了
如果是对方的应答报文丢失而导致发送方进行超时重传,此时接收方就会再次收到一个重复的报文数据。
如何处理这个重复的报文?
数据超时的时间如何确定??即定时器的时间有多长??
TCP为了保证无论在任何环境下都能比较高性能的通信,因此会动态计算这个最大超时时间
BSD Unix
和Windows
也是如此),超时以500ms
为一个单位进行控制,每次判定超时重发的超时时间都是500ms
的整数倍2*500ms
后再进行重传4*500ms
进行重传,依次类推,以指数形式递增文章内容太多,下一篇见(以上就已经有一万字了,TCP内容真多…)
--------------------- END ----------------------
「 作者 」 枫叶先生
「 更新 」 2023.7.21
「 声明 」 余之才疏学浅,故所撰文疏漏难免,
或有谬误或不准确之处,敬请读者批评指正。