2.5 TCP网络协议

news2024/11/28 14:06:48

一、TCP协议网络开发API

1、传输控制块(TCB)

传输控制块(TCB)是TCP协议的核心数据结构之一,它用于维护TCP连接状态和处理TCP数据传输。每个TCP连接都有一个对应的TCB,其中包含了该连接的相关信息,如序列号、确认号、窗口大小等。
在TCP连接过程中,TCB扮演着非常重要的角色。例如,在建立连接时,客户端和服务器端会相互发送SYN和ACK消息来协商初始序列号等信息,在这个过程中就需要使用到TCB;在数据传输阶段,每次发送或接收数据都需要更新TCB中的相关字段,以便双方能够正确地维护连接状态。

2、TCP服务端调用的API

// 1、socket
在文件系统中分配一个fd,并创建TCB数据结构。
int socket(int domain, int type, int protocol) 
// 2、bind
将TCP的socket绑定本地IP地址和端口。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
// 3、listen
将TCP置于LISTEN状态。
int listen(int sockfd, int backlog);
// 4、accept
从全连接队列中取出一个节点,并分配一个fd。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
// 5、recv
在对应fd中,从读缓冲区中拷贝出数据。
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
// 6、send
把fd对应的TCB数据拷贝到写缓冲区中。
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
// 7、close
准备一个FIN包,放到写缓冲区,是否关闭连接。
int close(int fd);

3、TCP客户端调用的API有:

// 1、socket
int socket(int domain, int type, int protocol)
// 2、bind
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
// 3、connect
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
// 4、recv
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
// 5、send
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
// 6、close
int close(int fd);

二、TCP 建立连接

1、TCP首部行说明

TCP是一个面向连接的协议。无论哪一方向另一方发送数据之前,都必须先在双方之间
建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。同时由于TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP是全双工模式,所以需要四次挥手关闭连接。

下面的图是TCP首部的数据格式,它定义了TCP协议如何读取和解析数据:
在这里插入图片描述

  1. TCP端口号
    每个TCP段都包含源端和目的端的端口号,用于寻找发端和收端应用进程。这两个值加
    上IP首部中的源端IP地址和目的端IP地址唯一确定一个TCP连接。
    (五元组:源端IP + 源端端口号 + 目的端IP + 目的端端口号 + 协议)

  2. TCP的序号
    32位序号 seq:Sequence number 缩写seq ,用来标识从TCP发端向TCP收端发送的数据字节流,它表示在这个报文段中的的第一个数据字节。在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。

  3. TCP的确认号
    32位确认号 ack:Acknowledge number 缩写ack,TCP对上一次seq序号做出的确认号,用来响应TCP报文段,给收到的TCP报文段的序号seq加1。指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。

  4. TCP的标志位
    SYN:同步标志位,用于建立会话连接,同步序列号;
    ACK: 确认标志位,对已接收的数据包进行确认;
    FIN: 完成标志位,表示发端完成发送任务,即将关闭连接;
    PSH:推送标志位,表示该数据包被对方接收后应立即交给上层应用,而不在缓冲区排队;
    RST:重置标志位,用于连接复位、拒绝错误和非法的数据包;
    URG:紧急标志位,表示数据包的紧急指针域有效,用来保证连接不被阻断,并督促中间设备尽快处理;

2、TCP三次握手

在这里插入图片描述

一开始,客户端和服务端都处于 CLOSE 状态。先是服务端主动监听某个端口,处于 LISTEN 状态。

第一次握手
客户端将TCP首部标志位的SYN置1,表示SYN报文。并随即产生一个TCP首部的序号值seq=x。接着把第一个SYN报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据。之后,客户端进入SYN_SENT状态,等待服务器端确认。

第二次握手
服务端收到客户端的SYN报文后,首先服务端也随机产生一个TCP首部的序号值seq=y,其次把TCP首部的确认号置为ack=x+1,接着把TCP首部标志位的SYN和ACK置为1。最后把该报文发给客户端,该报文也不包含应用层数据,服务器端进入SYN_RCVD状态。

第三次握手
客户端收到服务端报文后,还要向服务端回应最后一个应答报文。首先该应答报文 TCP 首部标志位的ACK置为 1 ,其次TCP首部的确认号置为ack=y+1 ,最后把报文发送给服务端,这次报文可以携带客户到服务端的数据,之后客户端处于 ESTABLISHED 状态。

服务端收到客户端的应答报文后,也进入 ESTABLISHED 状态。

从上面的过程可以发现第三次握手是可以携带数据的,前两次握手是不可以携带数据的。

3、为何只用三次握手

(来自小林图解网络)
TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输。

  1. 防止历史连接的建立:
    在两次握手的情况下,假设服务端在收到历史连接的SYN 报文后,就会进入 ESTABLISHED 状态,并给客户端发送ACK确认报文。客户端收到ACK确认报文,判断到此次连接为历史连接,那么就会回 RST 报文来断开连接。
    可以看到,如果采用两次握手建立 TCP 连接的场景下,服务端在向客户端发送数据前,并没有阻止掉历史连接,导致服务端建立了一个历史连接,又白白发送了数据,浪费了服务端的资源。
  2. 帮助双方同步初始化序列号
    TCP 协议的通信双方, 都必须维护一个「序列号」seq, 序列号是可靠传输的一个关键因素,它的作用:
    ·接收方可以去除重复的数据;
    ·接收方可以根据数据包的序列号按序接收;
    ·可以标识发送出去的数据包中, 哪些是已经被对方收到的(通过 ACK 报文中的序列号知道);
    可见,序列号在 TCP 连接中占据着非常重要的作用,所以当客户端发送携带「初始序列号」的 SYN 报文的时候,需要服务端回一个 ACK 应答报文,表示客户端的 SYN 报文已被服务端成功接收,那当服务端发送「初始序列号」给客户端的时候,依然也要得到客户端的应答回应,这样一来一回,才能确保双方的初始序列号能被可靠的同步。

举个例子,现实生活中的人与人打电话
“喂,你听得到吗?”
“我听得到呀,你听得到我吗?”
“我能听到你“
经过三次的互相确认,大家就会认为对方对听的到自己说话,并且愿意下一步沟通,否则,对话就不一定能正常下去了。

3、全连接和半连接

全连接和半连接是TCP协议中的两种连接状态。
半连接
半连接也称为不完全连接,是指在进行TCP三次握手后只建立了一部分的连接状态。在半连接状态下,仅有一方可以向对方发送数据,而对方不能回复。当接收到请求端发送的SYN报文时,被请求端会返回一个ACK报文确认该SYN已收到,并同时发送自己的SYN报文作为回应。但此时并没有完整建立起TCP链接。

全连接
全连接也称为完全连接,是指在进行TCP三次握手后建立的一种稳定的、可靠的连接状态。在全连接状态下,双方可以互相发送数据,并且保证数据传输的可靠性和顺序性。
在这里插入图片描述

三、TCP传输数据

使用send()函数发送数据时,返回正数不一定代表发送成功,仅仅表示成功将数据拷贝到内核协议栈的tcb,再由协议栈发送;发送过程中会经过N个网关,可能存在丢包或链路断开导致未能发送到目的地。如果要知道数据是否发送成功,需要加上确认机制(ACK)。
在这里插入图片描述

四、TCP 断开连接

1、四次挥手

在这里插入图片描述
第一次挥手
客户端发起关闭请求,向服务端发送TCP首部标志位FIN = 1、ACK = 1的报文段,之后客户端进入FIN_WAIT_1状态。

第二次挥手
服务端收到该报文后,向客户端发送标志位ACK = 1的确认报文段,接着服务端进入CLOSE_WAIT状态。
客户端收到服务吨的ACK确认报文段后,进入FIN_WAIT_2状态。

第三次挥手
服务端处理完数据之后,也向客户端发送TCP首部标志位FIN = 1、ACK = 1的报文段,之后服务端进入LAST_ACK状态。

第四次挥手
客户端收到服务端发送的FIN报文后,回复标志位是ACK的报文段,之后入客户端TIME_WAIT状态。
服务端收到客户端的ACK确认报文后,就进入CLOSE状态,至此服务端已经完成连接的关闭。
客户端在等待2MSL的时间后没有收到回复,自动进入CLOSE状态,至此服务端也已经完成连接的关闭

2、问题

(以下来自小林图解网络)
1)为什么需要四次挥手
关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
服务端收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。
从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,因此是需要四次挥手。

2)为什么会出现三次挥手
当被动关闭方在 TCP 挥手过程中,没有数据要发送并且开启了 TCP 延迟确认机制,那么第二和第三次挥手就会合并传输,这样就出现了三次挥手。
在这里插入图片描述
当发送没有携带数据的 ACK,它的网络效率也是很低的,因为它也有 40 个字节的 IP 头 和 TCP 头,但却没有携带数据报文。 为了解决 ACK 传输效率低问题,所以就衍生出了 TCP 延迟确认。 TCP 延迟确认的策略:
-当有响应数据要发送时,ACK 会随着响应数据一起立刻发送给对方
-当没有响应数据要发送时,ACK 将会延迟一段时间,以等待是否有响应数据可以一起发送
-如果在延迟等待发送 ACK 期间,对方的第二个数据报文又到达了,这时就会立刻发送 ACK

3)为什么需要 TIME_WAIT 状态?

  • 防止历史连接中的数据,被后面相同四元组的连接错误的接收;
    服务端在关闭连接之前发送的 seq= x 报文,但被网络延迟了。
    接着,服务端以相同的四元组重新打开了新连接,前面被延迟的 seq= x 这时抵达了客户端,而且该数据报文的序列号刚好在客户端接收窗口内,因此客户端会正常接收这个数据报文,但是这个数据报文是上一个连接残留下来的,这样就产生数据错乱等严重的问题。
    TCP 设计了 TIME_WAIT 状态,状态会持续 2MSL 时长,这个时间足以让两个方向上的数据包都被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接所产生的。
  • 保证「被动关闭连接」的一方,能被正确的关闭;
    如果客户端(主动关闭方)最后一次 ACK 报文(第四次挥手)在网络中丢失了,那么按照 TCP 可靠性原则,服务端(被动关闭方)会重发 FIN 报文。
    假设客户端没有 TIME_WAIT 状态,而是在发完最后一次回 ACK 报文就直接进入 CLOSE 状态,如果该 ACK 报文丢失了,服务端则重传的 FIN 报文,而这时客户端已经进入到关闭状态了,在收到服务端重传的 FIN 报文后,就会回 RST 报文。

4)服务器出现大量 CLOSE_WAIT 状态的原因有哪些?
CLOSE_WAIT 状态是「被动关闭方」才会有的状态,而且如果「被动关闭方」没有调用 close 函数关闭连接,那么就无法发出 FIN 报文,从而无法使得 CLOSE_WAIT 状态的连接转变为 LAST_ACK 状态。
所以,当服务端出现大量 CLOSE_WAIT 状态的连接的时候,说明服务端的程序没有调用 close 函数关闭连接。

5)如果已经建立了连接,但是客户端突然出现故障了怎么办?
客户端出现故障指的是客户端的主机发生了宕机,或者断电的场景。发生这种情况的时候,如果服务端一直不会发送数据给客户端,那么服务端是永远无法感知到客户端宕机这个事件的,也就是服务端的 TCP 连接将一直处于 ESTABLISHED 状态,占用着系统资源。
为了避免这种情况,TCP 存在一个保活机制:
定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP 保活机制会每隔一个时间间隔,发送一个探测报文,如果连续几个探测报文都没有得到响应,则认为当前的 TCP 连接已经死亡,系统内核将错误信息通知给上层应用程序。

五、TCP状态机

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/620103.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

地震勘探基础(十四)之地震反演

地震反演 反射波地震勘探主要是利用的是地下岩石的弹性差异特征,而弹性差异主要体现在波阻抗差异上。地震波垂直入射情况下,反射系数的公式告诉我们反射界面上下的波阻抗差异越大,反射系数越大,反射振幅也就相对较强。 利用反射波…

使用Hugo+Github从0开始免费搭建个人博客

环境搭建 一.安装git 以win11为例 1.注册git账号:https://github.com/并记住用户名和密码 2.下载地址:Git - Downloads (git-scm.com)鼠标右键显示Git Bash Here就表示安装Git成功了。 3.设置本地git用户 git config --global user.name "Your…

ROS 2 Humble 标定纠正畸变全景鱼眼展开网络摄像头

简介 本文使用 Ubuntu 系统,用 Python 开发 ROS 2 ,用 camera_calibration 功能包标定相机,用 OpenCV 读取视频帧和转换 ROS 2 图像话题,用 MediaMTX 搭建流媒体服务器, 用 FFmpeg 将视频帧输出为视频流。 最终效果: 环境准备 虚拟机 VMware Workstation 安装 Ubunt…

L9110S电机驱动模块demo

0.资料 项目工程文件夹 分文件原理 1.认识L9110S 1、概述: 一个L9110S驱动可以控制一个电机,图中左右两个黑色芯片就是L9110S驱动。当然如果会硬件也可以直接把它们设计到单片机开发板上。 一个电机由两个针脚控制,我们用杜邦线让L9110S…

MidJourney如何画出专业摄影师拍出的照片效果,附提示词

文 / 高扬(微信公众号:量子论) 最近沉迷于MidJourney作画,与ChatGPT相比,研究AI绘画,可以扩大自己的想像空间。 孩子的想像力更为丰富,如果家有宝宝,可以把孩子们的想法用AI绘画呈现…

面向对象的几大特性总结(适合秋招和小白学习的一篇文章)

前言: 本篇文章主要讲解面向对象的几大特性相关知识。该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读。 如果文章有什么需要改进的地方欢迎大佬提出,对大佬有帮助希望可以支持下哦~ 小威在此先感谢各位小伙伴儿了😁 以下正文开始 …

Doo Prime 德璞资本:怎么买黄金期货?黄金期货交易特点有哪些?

黄金期货是一种衍生品,是指在期货交易所上交易的黄金合约。作为一种高风险高收益的投资工具,有哪些黄金期货交易特点?本文围绕这一内容展开说明。 黄金期货交易特点一、需要开立账户 黄金期货是期货,如同股票投资要到证券公司开户一样,黄金期…

JVM | Java内存区域

JVM | Java内存区域 1、运行时数据区域1.1、程序计数器(线程私有)1.2、虚拟机栈(线程私有)1.3、本地方法栈(线程私有)1.4、堆(线程共享)1.5、方法区(元空间)(线程共享)1.6、直接内存(线程共享)2、HotSpot 虚拟机对象分配、布局和访问2.1、对象创建流程2.2、对象的…

【高危】Apache Inlong 存在JDBC反序列化漏洞

漏洞描述 Apache InLong 是可用于构建基于流式的数据分析、建模等一站式的海量数据集成框架。 在Apache Inlong受影响版本,由于未对接收的jdbcUrl参数过滤空格字符,导致可以利用空格绕过jdbcUrl中autoDeserialize参数过滤限制,通过认证的攻…

LegalAI领域大规模预训练语言模型的整理、总结及介绍(持续更新ing…)

诸神缄默不语-个人CSDN博文目录 最近更新日期:2023.6.7 最早更新日期:2023.6.7 文章目录 1. 通用大规模预训练语言模型2. 对话模型3. 分句 1. 通用大规模预训练语言模型 英语: LegalBERT 原始论文:(2020 EMNLP) LEGAL-BERT: Th…

Django - 页面静态化基本使用(一)

一. 前言 一个网页会有很多数据是不需要经常变动的,比如说首页,变动频率低而访问量大,我们可以把它静态化,这样就不需要每次有请求都要查询数据库再返回,可以减少服务器压力 我们可以使用Django的模板渲染功能完成页面…

Linux | SFTP

SFTP 文章目录 SFTPSSH 文件传输协议连接获取SFTP帮助查看及切换路径遍历远程文件系统访问本地的文件系统 传输文件传输本地文件到远程服务器简单的文件操作图形界面程序Reference欢迎关注公众号【三戒纪元】 SSH 文件传输协议 FTP,即文件传输协议,是一…

Java中的几种关键字详细介绍(秋招总结篇)

前言: 本篇文章主要讲解Java中的几种关键字相关知识。该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读。 如果文章有什么需要改进的地方欢迎大佬提出,对大佬有帮助希望可以支持下哦~ 小威在此先感谢各位小伙伴儿了😁 以下正文开始 文…

prometheus介绍与安装

prometheus介绍与安装 文章目录 prometheus介绍与安装一、Prometheus 简介1.Prometheus 优势2.Prometheus 基础架构 二、Prometheus 安装1.后端存储配置 三、使用 Prometheus 实现系统监控四、使用 Prometheus Grafana 实现可视化界面四.zabbixgrafana 安装部署参考http://t.c…

【Mininet】基础篇:开源控制器POX

大家好,我是文思月! 每文一言:时间不在于你拥有多少,而在于你如何使用! 本篇文章: 本篇文章主要是基于POX控制器进行的两个实验:一个是使交换机模拟hub(集线器)的功能&a…

逍遥自在学C语言 | 宏定义技巧让你的C代码快人一步

前言 在C语言中,宏定义是一种预处理指令,用于在代码中定义和使用常量、函数或代码片段的替代。 宏定义使用#define关键字来定义,并在代码中进行替换。宏定义具有以下优点: 简化代码:宏定义可以将一些常用的、重复出…

MySQL高可用集群解决方案之:lvs+keepalived+mysql cluster实现负载均衡

一:前言 Mysql-cluster本身实现了高可用,但是其sql节点并没有实现负载均衡。怎样让程序能均衡地访问sql节点呢,程序里写哪个数据库服务器IP呢? LVS是实现负载均衡作用的,即将客户端的需求采用特定的负载均衡算法分发…

在职考研 | 对于朝九晚五的上班族来说同等学力申硕更轻松!

我们要知道的是,考在职研究生的群体90%以上都是朝九晚五的上班族。 他们工作忙,时间和精力都很有限。 考研本身难度就很大,但是既拿不出足够多的备考时间,也没法到线下去上课。 怎么能考上呢? 在这样的现实条件下&…

yolov5部署到android studio

目录 环境获取demo将pt文件导出为ptl文件修改demo修改PrePostProcessor增加ptl文件并增加类别文件修改MainActivity 大功告成 环境 Ubuntu22.10 Pytorch2.0.1cu117 Android Studio Flamingo | 2022.2.1 Patch 1 获取demo git clone https://github.com/pytorch/android-demo…

self Attention 位置编码的奇偶输入问题

attention机制一直是放在encoder-decoder中进行使用,self-attention是为了解决前者结构无法并行计算,而抽离出的概念(前者的编码解码多为时序网络)。 但因为缺少时序模型天然的位置编码特点,所以self-attention模型需要…