linux三次握手、四次挥手
TCP协议是一个安全的、面向连接的、流式传输协议,所谓的面向连接就是三次握手,对于程序猿来说只需要在客户端调用connect()函数,三次握手就自动进行了。先通过下图看一下TCP协议的格式,然后再介绍三次握手的具体流程。
1.tcp协议介绍
在Tcp协议中,比较重要的字段有:
- 源端口:表示发送端端口号,字段长 16 位,2个字节
- 目的端口:表示接收端端口号,字段长 16 位,2个字节
- 序号(sequence number):字段长 32 位,占4个字节,序号的范围为 [0,4284967296]。
- 由于TCP是面向字节流的,在一个TCP连接中传送的字节流中的每一个字节都按顺序编号
- 首部中的序号字段则是指本报文段所发送的数据的第一个字节的序号,这是随机生成的。
- 序号是循环使用的,当序号增加到最大值时,下一个序号就又回到了0
- 确认序号(acknowledgement number):占32位(4字节),表示收到的下一个报文段的第一个数据字节的序号,如果确认序号为N,序号为S,则表明到序号N-S为止的所有数据字节都已经被正确地接收到了。
- 8个标志位(Flag):
- CWR:CWR 标志与后面的 ECE 标志都用于 IP 首部的 ECN 字段,ECE 标志为 1 时,则通知对方已将拥塞窗口缩小;
- ECE:若其值为 1 则会通知对方,从对方到这边的网络有阻塞。在收到数据包的 IP 首部中 ECN 为 1 时将 TCP 首部中的 ECE 设为 1.;
- URG:该位设为 1,表示包中有需要紧急处理的数据,对于需要紧急处理的数据,与后面的紧急指针有关;
- ACK:该位设为 1,确认应答的字段有效,TCP规定除了最初建立连接时的 SYN 包之外该位必须设为 1;
- PSH:该位设为 1,表示需要将收到的数据立刻传给上层应用协议,若设为 0,则先将数据进行缓存;
- RST:该位设为 1,表示 TCP 连接出现异常必须强制断开连接;
- SYN:用于建立连接,该位设为 1,表示希望建立连接,并在其序列号的字段进行序列号初值设定;
- FIN:该位设为 1,表示今后不再有数据发送,希望断开连接。
- 窗口大小:该字段长 16 位,表示从确认序号所指位置开始能够接收的数据大小,TCP 不允许发送超过该窗口大小的数据。
2.三次握手
Tcp连接是双向连接,客户端和服务器需要分别向对方发送连接请求,并且建立连接,三次握手成功之后,二者之间的双向连接也就成功建立了。如果要保证三次握手顺利完成,必须要满足以下条件:
- 服务器端:已经启动,并且启动了监听(被动接受连接的一端)
- 客户端:基于服务器端监听的IP和端口,向服务器端发起连接请求(主动发起连接的一端)
三次握手具体过程如下:
第一次握手:
- 客户端:客户端向服务器端发起连接请求将报文中的SYN字段置为1,生成随机序号x,seq=x
- 服务器端:接收客户端发送的请求数据,解析tcp协议,校验SYN标志位是否为1,并得到序号 x
第二次握手:
- 服务器端:给客户端回复数据
1.回复ACK, 将tcp协议ACK对应的标志位设置为1,表示同意了客户端建立连接的请求
2.回复了 ack=x+1, 这是确认序号
- x: 客户端生成的随机序号
- 1: 客户端给服务器发送的数据的量, SYN标志位存储到某一个字节中, 因此按照一个字节计算,表示客户端给服务器发送的1个字节服务器收到了。
3.将tcp协议中的SYN对应的标志位设置为 1, 服务器向客户端发起了连接请求
4.服务器端生成了一个随机序号 y, 发送给了客户端
- 客户端:接收回复的数据,并解析tcp协议
- 校验ACK标志位,为1表示服务器接收了客户端的连接请求
- 数据校验,确认发送给服务器的数据服务器收到了没有,计算公式如下:发送的数据的量 = 使用服务器回复的确认序号 - 客户端生成的随机序号 ===> 1=x+1-x
- 校验SYN标志位,为1表示服务器请求和客户端建立连接
- 得到服务器生成的随机序号: y
第三次握手:
- 客户端:发送数据给服务器
1.将tcp协议中ACK标志位设置为1,表示同意了服务器的连接请求
2.给服务器回复了一个确认序号 ack = y+1
- y:服务器端生成的随机序号
- 1:服务器给客户端发送的数据量,服务器给客户端发送了ACK和SYN, 都存储在这一个字节中
3.发送给服务器的序号就是上一次从服务器端收的确认序号因此 seq = x+1
- 服务器端:接收数据, 并解析tcp协议
- 查看ACK对应的标志位是否为1, 如果是1代表, 客户端同意了服务器的连接请求
- 数据校验,确认发送给客户端的数据客户端收到了没有,计算公式如下:给客户端发送的数据量 = 确认序号 - 服务器生成的随机序号 ===> 1=y+1-y
- 得到客户端发送的序号:x+1
3.tcp四次挥手
四次挥手是断开连接的过程,需要双向断开,关于由哪一端先断开连接是没有要求的。通信的两端如果想要断开连接就需要调用close()函数,当两端都调用了该函数,四次挥手也就完成了。
- 客户端和服务器断开连接 -> 单向断开
- 服务器和客户端断开连接 -> 单向断开
进行了两次单向断开,双向断开就完成了,每进行一次单向断开,就会完成两次挥手的动作。
- 第一次挥手:
- 主动断开连接的一方:发送断开连接的请求
- 将tcp协议中FIN标志位设置为1,表示请求断开连接
- 发送序号x给对端,seq=x,基于这个序号用于客户端数据校验的计算
- 被动断开连接的一方:接收请求数据, 并解析TCP协议
- 校验FIN标志位是否为1
- 收到了序号 x,基于这个数据计算回复的确认序号 ack 的值
第二次挥手:
- 被动断开连接的一方:回复数据
- 同意了对方断开连接的请求,将ACK标志位设置为1
- 回复 ack=x+1,表示成功接受了客户端发送的一个字节数据
- 向客户端发送序号 seq=y,基于这个序号用于服务器端数据校验的计算
- 主动断开连接的一方:接收回复数据, 并解析TCP协议
- 校验ACK标志位,如果为1表示断开连接的请求对方已经同意了
- 校验 ack确认发送的数据服务器是否收到了,发送的数据 = ack - x = x + 1 -x = 1
第三次挥手:
- 被动断开连接的一方:将tcp协议中FIN标志位设置为1,表示请求断开连接
- 主动断开连接的一方:接收请求数据, 并解析TCP协议,校验FIN标志位是否为1
第四次挥手:
- 主动断开连接的一方:回复数据
- 将tcp协议中ACK对应的标志位设置为1,表示同意了断开连接的请求
- ack=y+1,表示服务器发送给客户端的一个字节客户端接收到了
- 序号 seq=h,此时的h应该等于 x+1,也就是第三次挥手时服务器回复的确认序号ack的值
- 被动断开连接的一方:收到回复的ACK, 此时双向连接双向断开, 通信的两端没有任何关系了
4.流量控制
流量控制可以让发送端根据接收端的实际接受能力控制发送的数据量。它的具体操作是,接收端主机向发送端主机通知自己可以接收数据的大小,于是发送端会发送不会超过该大小的数据,该限制大小即为窗口大小,即窗口大小由接收端主机决定。
TCP 首部中,专门有一个字段来通知窗口大小,接收主机将自己可以接收的缓冲区大小放在该字段中通知发送端。当接收端的缓冲区面临数据溢出时,窗口大小的值也是随之改变,设置为一个更小的值通知发送端,从而控制数据的发送量,这样达到流量的控制。这个控制流程的窗口也可以称作滑动窗口。
这个图是一个单向的数据发送:
左侧是数据发送端:对应的是发送端的写缓冲区(内存),通过一个环形队列进行数据管理
- 白色格子: 空闲的内存, 可以写数据
- 粉色的格子: 被写入到内存, 但是还没有被发送出去的数据
- 灰色的格子: 代表已经被发送出去的数据
右侧是数据接收端:对应的是接收端的读缓冲区,存储发送端发送过来的数据
- 白色格子:空闲的内存, 可以继续接收数据, 滑动窗口的值记录的就是白色的格子的大小
- 随着接收的数据越来越多, 白色格子越来越少, 滑动窗口的值越来越小
- 如果白色格子没有了, 滑动窗口变为0, 这时候, 发送端就被阻塞了
- 粉色格子:接收的数据,但是这个数据还没有从内核中读走,使用read() / recv()
- 粉色格子变少了, 可用空间就变多了, 滑动窗口的值就变大了
- 如果滑动窗口的值从0变为大于0, 接收端又重新有容量接收数据了, 发送端的阻塞自动解除,继续发送数据
基于TCP通信的流程图,记录了从三次握手 -> 数据通信 -> 四次挥手是全过程:
# fast sender: 客户端
# slow recerver: 服务器
# win: 滑动窗口大小
# mss: maximum segment size, 单条数据的最大长度
第1步:第一次握手,发送连接请求SYN到服务器端
- 0(0):0表示客户端生成的随机序号,(0)表示客户端没有额外给服务器发送数据, 因此数据的量为0
- win4096: 客户端告诉服务器, 能接收的数据(缓存)的最大量为4k
- mss1460: 客户端可以处理的单条最大字节数是1460字节
第2步:第二次握手
- ACK: 服务器同意了客户端的连接请求
- SYN: 服务器请求和客户端建立连接
- 8000(0):8000是服务器端生成的随机序号,(0)表示服务器没有额外给客户端发送数据, 因此数据的量为0
- 1: 发送给客户端的确认序号
- 确认序号 = 客户端生成的随机序号 + 客户端给服务器发送的数据量(字节数) ===> 1=0+1
- 表示客户端给服务器发送的1个字节服务器收到了
- win6144: 服务器告诉客户端我能最多缓存 6k数据
- mss1024: 服务器能处理的单条数据最大长度是 1k
第3步: 第三次握手
- ACK: 客户端同意了服务器的连接请求
- 8001: 发送给服务器的确认序号
- 确认序号 = 服务器生成的随机序号 + 服务器给客户端发送的数据量 ===> 8001 = 8000 + 1
- 客户端告诉服务器, 你给我发送的1个字节的数据我收到了
- win4096: 告诉服务器客户端能缓存的最大数据量是4k
第4~9步: 客户端给服务器发送数据
- 1(1024):1 (1-0)表示之前一共给服务器发送了1个字节,(1024)表示这次要发送的数据量为 1k
- 1025(1024):1025(1025-0)表示之前一共给服务器发送了1025个字节,(1024)表示这次要发送的数据量为 1k
- 2049(1024):2049(2049-0)表示之前一共给服务器发送了2049个字节,(1024)表示这次要发送的数据量为 1k
- 第9步完成之后,服务器的滑动窗口变为0,接收数据的缓存被写满了,发送端阻塞
第10步:
- ack6145: 服务器给客户端回复数据,6145是确认序号, 代表实际接收的字节数服务器实际接收的字节数 = 确认序号 - 客户端生成的随机序号 ===> 6145 = 6145 - 0
- win2048:服务器告诉客户端我的缓存还有2k,也就是还有4k还在缓存中没有被读走
第11步:win4096表示滑动窗口变为4k,代表还可以接收4k数据,还有2k在缓存中
第12步:客户端又给服务器发送了1k数据
第13步: 第一次挥手,FIN表示客户端主动和服务器断开连接,并且发送了1k数据到服务器端
第14步: 第二次挥手,回复ACK, 同意断开连接
第15, 16步: 服务器端从读缓冲区中读数据, 第16步数据读完, 滑动窗口变成最大的6k
第17步:
- FIN: 服务器请求和客户端断开连接
- 8001(0): 服务器一共给客户端发送的字节数 8001 - 8000 = 1个字节,携带的数据量为0(FIN不计算在内)
- ack8194: 服务器收到了客户端的多少个字节: 8194 - 0 = 8194个字节
第18步: 第四次挥手
- ACK: 客户端同意了服务器断开连接的请求
- 8002: 确认序号, 可以计算出服务器给客户端发送了多少数据,8002 - 8000 = 2 个字节
相关文章:

linux三次握手、四次挥手
TCP协议是一个安全的、面向连接的、流式传输协议,所谓的面向连接就是三次握手,对于程序猿来说只需要在客户端调用connect()函数,三次握手就自动进行了。先通过下图看一下TCP协议的格式,然后再介绍三次握手的具体流程。 1.tcp协议…...

C# 泛型介绍
C# 中的泛型(Generics)是一种强类型参数化的特性,它允许你编写不具体指定数据类型的代码,而在实际使用时再指定具体的类型。泛型的引入使得代码更加灵活、可重用,并提高了类型安全性。 C#泛型基本用法 以下是一个简单…...

Windows如何正确设置PHP环境变量以在Git Bash中运行命令
1、随便找一个目录,鼠标右键打开git bash here 2、cd的根目录 3、找到php安装目录 4、 在根目录下打开 vim .bash_profile ,添加环境变量,php地址根据自己的本地地址而定 PATH$PATH:/d/phpstudy_pro/Extensions/php/php7.3.4nts 添加后保存…...

[代码实战和详解]VGG16
VGG16 详解 我的github代码实现:vgg16 我们在vgg16神经网络上训练了SIGNS数据集,这是一个分类的数据集,在我的github上有介绍怎么下载数据集以及如何训练。 VGG16是一个卷积神经网络(CNN)架构,它在2014年…...

x3daudio1_7.dll错误:解决方法和丢失原因及作用
x3daudio1_7.dll是Windows操作系统中的一个动态链接库(DLL)文件,主要作用是为DirectX音频提供支持。DirectX是微软推出的一套多媒体应用程序开发接口,广泛应用于游戏、多媒体制作等领域。x3daudio1_7.dll文件包含了许多与三维音频…...

pipeline + node +jenkins+kubernetes部署yarn前端项目
1、编写Dockerfile文件 # Set the base image FROM node:16.10.0# WORKDIR /usr/src/app/ WORKDIR /home/option# Copy files COPY ./ /home/option/# Build arguments LABEL branch${BRANCH} LABEL commit${COMMIT} LABEL date${BUILD_DATE} ARG ENV# Set ENV variables ENV …...

计算机网络中的面向连接与无连接
目录 面向连接和无连接在计算机网络中是如何理解的面向连接和无连接的通信在路由选择上有哪些区别 面向连接和无连接在计算机网络中是如何理解的 在计算机网络中,面向连接和无连接是两种核心的网络通信方式,它们决定了数据包如何传输和接收。 面向连接&…...

EventEmitter3在vue中的使用
前提 vue中的组件传递方式有很多,包括父子组件之间的传值(props,emit)、事件总线($ bus)、状态管理模式(vuex,pinia),现在推荐一种可以替代$bus的一种传值方…...

双剑合璧:基于Elasticsearch的两路召回语义检索系统,实现关键字与语义的高效精准匹配
搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术…...

LeetCode34-34. 在排序数组中查找元素的第一个和最后一个位置
🔗:代码随想录:二分查找的算法讲解:有关left<right和left<right的区别 class Solution {public int[] searchRange(int[] nums, int target) {int nnums.length;int l0,hn-1;if(numsnull){return null; }if(n0){return new int[]{-1,-1}; }if(target&l…...

ddrnet 分割学习笔记
目录 修改后可以加载预训练: 训练自己的数据代码: 默认分割后特征下采样8倍,最后用上采样恢复到原图; 修改后可以加载预训练: import math import torch import numpy as np import torch.nn as nn import torch.nn.functional as F from torch.nn import init from …...

Outlook关闭过去事件的提醒
Outlook关闭过去事件的提醒 故障现象 最近Outlook中推出的新功能让我们可以选择自动关闭过去事件的提醒。 目前这个功能暂时只向当月通道的Office 365 订阅者发布。 这些用户升级到1810版本后,可以在不想收到已发生事件提醒的时候通过下面的步骤自动忽略过去事件…...

git 简单入门
git init touch test.txt git add test.txt git commit -m 初始化 仓库 git log //查找日志 git checkout -b dev //创建并切换dev分支 git branch // 查找分支 此时有master 和 dev分支, 此时在dev分支 dev分支也有test.txt文件 vim test.txt //写入dev …...

只有开源才能拯救AI
导语 | 随着 AI 技术的蓬勃发展,大模型的开源化正成为人工智能领域的新潮流,但同时引发的伦理和安全风险也饱受大家关注,如何把握平衡其中的尺度成为开源的一大难题。我们又应该如何有效进行开源治理?未来将走向何方?今…...

在Spring Boot中使用进程内缓存和Cache注解
在Spring Boot中使用内缓存的时候需要预先知道什么是内缓存,使用内缓存的好处。 什么是内缓存 内缓存(也称为进程内缓存或本地缓存)是指将数据存储在应用程序的内存中,以便在需要时快速访问和检索数据,而无需每次都从…...

YOLOv5项目实战(3)— 如何批量命名数据集中的图片
前言:Hello大家好,我是小哥谈。本节课就教大家如何去批量命名数据集中的图片,希望大家学习之后可以有所收获!~🌈 前期回顾: YOLOv5项目实战(1)— 如何去训练模型 YOLOv5项目实战(2...

React + hooks + Ts 实现将后端响应的文件流(如Pdf)输出到浏览器下载
React 篇 一些关于react 学习与总结 这篇是记录开发中关于实现将后端响应的文件流(如Pdf)输出到浏览器下载,基于React Hooks Ts。 开发场景: 实现将后端响应的文件流(如Pdf)输出到浏览器下载,…...

大数据基础设施搭建 - JDK
一、创建目录 需要在root账号下操作,因为/目录下只能用root账号创建目录 1.1 创建目录 [roothadoop102 ~]# mkdir /opt/software/ [roothadoop102 ~]# mkdir /opt/module/1.2 修改权限 修改module、software文件夹的所有者和所属组均为hadoop用户,远程使…...

从0到0.01入门React | 010.精选 React 面试题
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…...

Docker启动SRS流媒体服务器
一、安装Docker 1.1、下载windows桌面版Windows 1.2、配置镜像 镜像加速器镜像加速器地址Docker 中国官方镜像https://registry.docker-cn.comDaoCloud 镜像站http://f1361db2.m.daocloud.ioAzure 中国镜像https://dockerhub.azk8s.cn科大镜像站https://docker.mirrors.ustc…...

php+MySQL防止sql注入
1、使用预处理语句(Prepared Statements):预处理语句能够防止攻击者利用用户输入来篡改SQL语句,同时也能提高执行效率。通过将用户的输入参数与SQL语句分离,确保参数以安全的方式传递给数据库引擎,避免拼接…...

git 删除远程非主分支
git删除远程分支问题及git批量删除已合并的远程分支 - joshua317的博客 git push origin --delete branch-name 本版本Gitlab没有设置按钮,所以不能在网页上删除项目。但是可以在本地使用上述命令来删除远程仓库中非主分支的分支。 测试过不论在哪个分支操作都可…...

【MySQL学习】C++外部调用
#include "mysql.h" MYSQL *mysql; MYSQL_RES *rec; MYSQL_ROW row; (1)连接 char *server "localhost"; char *user "root"; char *password "hello"; char *database "mysql"; mysql mysql_i…...

Backblaze 2023 Q3硬盘故障质量报告解读
作为一家在2021年在美国纳斯达克上市的云端备份公司,Backblaze一直保持着对外定期发布HDD和SSD的故障率稳定性质量报告,给大家提供了一份真实应用场景下的稳定性分析参考数据。2023年度之前发布的两次报告,请参考: Backblaze发布2…...

docker安装elasticsearch,elasticsearch-head
安装elasticsearch 1、执行命令:docker pull elasticsearch:8.11.1 2、执行命令:docker run --name elastic -p 9200:9200 -p 9300:9300 -e "discovery.typesingle-node" -d elasticsearch:8.11.1 3、执行命令:docker exec -it …...

rabbitmq 集群搭建
RabbitMQ集群介绍 RabbitMQ集群是一组RabbitMQ节点(broker)的集合,它们一起工作以提供高可用性和可伸缩性服务。 RabbitMQ集群中的节点可以在同一物理服务器或不同的物理服务器上运行。 RabbitMQ集群的工作原理是,每个节点在一个…...

【云原生-Kurbernets篇】Kurbernets集群的调度策略
调度 一、Kurbernetes的list-watch机制1.1 list-watch机制简介1.2 创建pod的流程(结合list-watch机制) 二、Scheduler的调度策略2.1 简介2.2 预选策略(predicate)2.3 优选策略(priorities) 三、标签管理3.1…...

Unity中Shader矩阵的乘法
文章目录 前言一、矩阵乘以标量二、矩阵和矩阵相乘1、第一个矩阵的列数必须 与 第二个矩阵的行数相等,否则无法相乘!2、相乘的结果矩阵,行数由第一个矩阵的行数决定,列数由第二个矩阵的列数决定! 三、单位矩阵四、矩阵…...

C++ STL简介
1. 什么是STL STL(standard template libaray-标准模板库):是C标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。 2. STL的版本 原始版本 Alexander Stepanov、Meng Lee 在惠普实验室…...

如何优雅的使用contorller层
一个完整的后端请求由 4 部分组成: 接口地址(也就是 URL 地址)请求方式(一般就是 get、set,当然还有 put、delete)请求数据(request,有 head 跟 body)响应数据ÿ…...