ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【Linux网络】TCP协议 [打印本页]

作者: 何小豆儿在此    时间: 2024-8-17 13:58
标题: 【Linux网络】TCP协议

     欢迎来到 破晓的进程的 博客   
     ⛺️不负时光,不负己✈️    

  
引言

TCP协议是传输层中非常重要的协议。本篇博客我们将从TCP头部信息、TCP状态转移、TCP数据流、TCP数据流的控制等等方面来讨论!
在TCP协议中,通讯两边的职位是平等的。不存在哀求和相应。
1、TCP协议的特点

传输层中我们常用的协议有两个:TCP协议和UDP协议。TCP协议相对于UDP协议的特点是:面向连接、可靠的、面向字节流的。
使用TCP协议通讯的两边在通讯之前必须建立连接,然后才气开始进行数据的读写。两边都必须为该连接分配须要的内核资源,以管理连接的状态和连接上数据的传输。TCP连接是全双工的,即一方在向对方发送数据的同时,并不妨碍对方向该方发送数据;数据可以在两个方向上同时传输,而这两个方向的传输是相互独立的,互不干扰。完成数据交换后,通讯两边必须断开连接,同时释放连接所占用的网络资源。

在讲它们的区别之前,我们必要了解一下TCP协议全双工的特点

TCP协议属于传输层中的协议,传输层由操作系统管理。在建立连接后,操作系统会为通讯两边在内核中创建相应的数据结构和读写缓冲区,通讯两边的内核中都有发送缓冲区和接收缓冲区。数据在接收和发送缓冲区内是分离的
那我们在应用层中调用write和read是在干什么呢?
就write函数而言,我们调用write函数就是要告诉操作系统这里有数据要传输,此时的数据就会被拷贝到该端的发送缓冲区中,应用层就返回了。该数据何时发送给对端,数据在传输过程中出现丢包的情况怎么办?这一切由操作系统和TCP协议决定,用户层只是给出建议。所以TCP协议又被称为传输控制协议。

由于两边可以同时向对方发送数据,所以这种通讯模式被称为全双工。


   我们知道TCP协议是面向字节流的,但UDP协议确是面向数据报的,字节流和数据报有什么区别呢?
  学到现在,信赖大家已经完成了TCP和UDP通讯的编码了。字节流和数据报的区别对应到编码中就是通讯两边是否必须执行相同次数的读写操作【这只是表现情势】。
当发送端应用程序一连执行多次写操作时,TCP模块先将这些数据放入TCP发送缓冲区中。当TCP模块真正开始发送数据时,发送缓冲区中这些等待发送的数据大概被封装成一个或者多个TCP报文发出去,因此,TCP模块发送出的TCP报文段的个数和应用程序执行的写操作次数没有固定的数量关系。
当接收缓冲区收到一个或者多个TCP报文后,TCP模块将它们携带的应用程序的数据按照TCP报文的序号【见下文】依次放入TCP接收缓冲区中,并通知应用程序读取数据。接收端应用程序可以一次性的将TCP接收缓冲区内的数据全部读出,也可以分多次读取器,这取决于用户指定的应用程序缓冲区大小。因此,应用程序执行的读操作次数和TCP模块接收到的TCP报文段个数之间没有固定的数量关系。
所以,发送端执行的写操作次数和接收端执行的读操作次数之间没有任何的数量关系,这就是字节流的概念:应用程序对数据的接收和发送是没有界限限定的。UDP则不然,发送端应用程序每执行一次写操作,UDP模块就将其封装成一个UDP数据报并发送之。接收端必须及时针对每一个UDP数据报进行读操作,假如没能及时读取数据报,就有大概发生丢包现象【这经常发生在一些较慢的服务器上】。并且假如用户没有足够的应用程序缓冲区来读取UDP数据,则UDP数据将被截断。
如图所示:

2、确认应答机制

为了使TCP通讯更具有可靠性,TCP协议采用了确认应答机制:即发送端发的每一个报文都必须得到对方的应答,才认为这个TCP报文传输乐成。其次TCP还采用了超时重传机制,发送端在发送一个TCP报文后启动定时器,假如在约定时间内没有收到对方对该报文的应答信息,发送段将重新发送该报文。并且TCP报文末了是以IP数据报的情势发送的,而IP数据报到达对端大概会出现乱序、重复等情况,所以TCP接收端还要对接收到的报文进行去重、排序等操作,然后再通知应用层读取数据。

这种通讯方式就比如做两个人交谈,一问一答,比及答复完上一个问题,再问下一个问题。
但是,也有大概会出现一个人语速很快的情况,一口气问了几个问题。答复问题的人只能比及所有问题都提出完,然后从第一个问题开始答复。如下图:

但是我们怎么将报文和应答一一对应起来呢?
在TCP报头中【后面讲】有一个字段为32位确认号【ACK】。该字段用来作为对另一方发来的数据的应答,其值为已经确认收到的序列号+1,表示确认号之前的所有报文而且是一连的都已收到。对没有收到应答的报文,采用超时重传机制。
   在通讯过程中,只必要对正常的报文进行确认,不必要对应答报文再次进行确认
  在TCP报头中,既存在32位序列号,又存在32位确认号。为什么要有两组序号呢?
一切的一切都归究于TCP是全双工协议。有大概这个报文既是对收到的报文的应答,同时也是一个新的哀求。
3、超时重传机制

对于高出时间限定但未收到应答的报文,TCP协议会重新传输;这也就决定了对已经发送到网络中的数据报的数据,我们不能立即丢弃,应该再保存一段时间,以防报文在传输过程中出现数据丢失的情况。
但是保存在那里呢?应该保存在TCP维护的发送缓冲区里。
TCP为了保证无论在任何环境下都能比较高性能的通讯, 因此会动态计算这个最大超时时间.

4、TCP报头结构


1、16位端口号
告知主机该报文来着那里【16位源端口号】以及要交给上层哪一个协议或者应用程序【16位目的端口号】。在使用TCP通讯时,客户端由操作系统和TCP协议动态绑定端口号,服务器则必要程序员绑定特定的端口号。

2、32位序列号
序列号:当前TCP报文中的第一个字节的序号。
一次TCP通讯(从TCP连接到断开)过程中某一个传输方向上的字节流的每一个字节编号。假设主机A和主机B进行TCP通讯,A向B发送的第一个报文中,序列号被系统初始化为某个随机值ISN。那么在该传输方向上(从A到B),后续的TCP报文段中序列号值将会被系统设置成ISN+该报文段所携带的数据的第一个字节在整个字节流中的偏移量。

3、32位确认序列号
用尴尬刁难另外一方发送来的TCP报文的响应。其值是收到的TCP报文段的序列号+1。假设主机A和主机B进行TCP通讯,那么A发送出的TCP报文不光要携带本身的序号,而且包含对B发送过来TCP报文端的确认号。反之,B发送的TCP报文段也同时包罗本身的序号和A发送过来的TCP报文端的确认号。

4、16位窗口大小
现在我们将TCP通讯两边看做两个人在当面交流。为了保证本身说的话可以准确的被对方获取,我们必要控制语言的速度。同理,为了保证TCP通讯的服从,只管减少丢包的概率,我们也应该控制TCP发送数据的速度,快了也不行,慢了也不行。
那什么指标可以看出接收方接收数据的本领呢?接收缓冲区剩余空间大小恰巧符合。这个数据是TCP流量控制的一种手段。
它告诉对方本端的TCP接受缓冲区还能容纳多少字节的数据,如许对方就可以控制发送数据的速度。

5、TCP标记位
有的TCP报文是一个哀求报文,内里包含着数据;有的TCP报文仅仅是对哀求的一个应答。那我们如何区分该报文的范例呢?TCP标记位
控制位由6个标志位组成,每个标志位占1位,总共6位。这些标志位可以单独设置,也可以组合设置,以表达差别的控制信息。
在现实应用中,控制位可以单独使用,也可以组合使用。例如:


5、16位校验和
由发送端填充,接收端对TCP报文段执行CRC算法以查验TCP报文段在传输过程中是否损坏。留意,这个查验不光包罗TCP头部,也包罗数据部分。这是TCP可靠性传输的一个重要保障

6、4位头部长度
标识该TCP头部有多少个32bit字(4字节)。因为4位最大能表示15,所以TCP头部最大是60个字节。

7、16位紧急指针
是一个正的偏移值。它和序号字段的值相加表示末了一个紧急数据的下一字节的序号。因此,准确的来说,这个字段是紧急指针先对于当前序号的偏移量。TCP紧急指针是发送端向接收端发送紧急数据的方法。
5、三次握手建立连接

三次握手是建立连接的方式,但不保证通过三次握手肯定建立连接乐成。
三次握手的过程如下:

过程用形象的例子来形容就是如下:

预备知识

   一次握手不行吗?
  答案是肯定不行的,因为如许极轻易浪费网络资源,造成SYN洪水。
两次握手也不行,会出现一次握手一样的问题。
那么,为社么三次握手就肯定可以呢?

6、四次挥手断开连接

如图:

   为什么挥手必要四次?
TCP的四次挥手是为了确保数据流的正确和可靠地关闭。这必要两边都明确地确认关闭哀求,并确保所有的数据包都已接收或处置处罚。通过四次握手,每一方都可以确认对方已经完成了数据传输和接收的准备工作。
  举个例子
张三和李四的对话
张三:好的,那我先走了
李四:好的,那你走吧
李四:那我也走了?
张三:好的,你走吧

四次挥手是指停止一个TCP连接的过程。它是TCP协议中用于正常关闭连接的机制。下面是四次挥手的具体流程:


接下来我们来分析一下四次挥手过程中通讯两边状态变革:
如图,OS内核会为TCP连接两边创建相应的11TCP状态【包罗三次握手过程中的5种状态和四次挥手断开过程中的6种状态】。
  1. typedef enum {  
  2.     CLOSED,         // 初始状态,表示TCP连接是"关闭着的"或"未打开的"  
  3.     LISTEN,         // 表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接  
  4.     SYN_SENT,       // 客户端发送SYN报文后等待服务端确认的状态  
  5.     SYN_RCVD,       // 服务端接收到客户端的SYN报文后的状态  
  6.     ESTABLISHED,    // TCP连接已经成功建立,开始传输数据  
  7.     FIN_WAIT_1,     // 客户端主动关闭连接,发送FIN报文后等待服务端确认  
  8.     FIN_WAIT_2,     // 客户端收到服务端的ACK确认后,等待服务端发送FIN报文  
  9.     CLOSE_WAIT,     // 服务端收到客户端的FIN报文后,等待关闭连接  
  10.     LAST_ACK,       // 服务端发送FIN报文后,等待客户端的ACK确认  
  11.     TIME_WAIT,      // 客户端在收到服务端的FIN报文并发送ACK后,进入TIME_WAIT状态  
  12.     CLOSING         // 一个特殊状态,双方同时关闭连接时可能出现  
  13. } TcpState;  
  14.   
  15. typedef struct {  
  16.     TcpState state;       // 当前TCP连接的状态  
  17.     // 其他可能的字段,如序列号、确认号、超时时间等,根据具体需求添加  
  18. } TcpConnectionState;
复制代码
  为什么 TIME_WAIT 等待的时间是 2MSL?
首先说什么是MSL,TTL,以及两者的关系
  MSL就是最大的报文生成时间,MSL是网络报文生存的最长时间,高出这个时间,报文将会被丢弃,因为TCP是基于IP协议的,TTL是经过路由器的最大跳数,每经过一个路由器,TTL就减一,当减到0的时候报文就会被丢弃,同时发送ICMP报文给源主机.
TTL 与 MSL的区别 : TTL是经过路由的最大跳数,MSL是报文生存的最长时间,要确保MSL>=TTL才气保证报文是正常灭亡.
   为什么要等待2MSL呢 ?
  原因是 在网络中大概来自觉送方发来的数据报,然后接收方要给对方一个响应. 如许报文一来一回的时间就是2MSL.
比如当末了一个ACK报文丢失(也就是第四次挥手丢失),服务器那边就会触发超时重传机制,重传FIN报文,当FIN报文到达客户端,客户端再回一个ACK响应,如许一来一回等待的时间是2MSL.
2MSL时长允许报文至少丢失一次,当ACK报文丢失的时候,重发的FIN会在第二个MSL到达客户端,如许TIME_WAIT状态就可以应对.2MSL是当第三次挥手到达客户端的时候就会开始计时,当中途FIN报文再次到达客户端,定时器就会被重置为2MSL.
   为什么不是 4MSL或者8MSL呢 ?
  由于丢包概率很小,参加丢包概率为1/100,那么第二次丢包就是1/10000, 所以我们可以忽略,性价比会更高。
总结



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4