Linux socket编程(5):三次握手和四次挥手分析和SIGPIPE信号的处理

news2024/11/16 4:16:04

在我之前写的Wireshark抓包:理解TCP三次握手和四次挥手过程中,通过抓包分析了TCP传输的三次握手和四次挥手的过程。在这一节中,将分析在Linux中的三次握手和四次挥手的状态和过程,另外还有一个在我们编程过程中值得注意的SIGPIPE信号的处理。

文章目录

  • 1 TCP连接的11种状态
  • 2 实验:查看TCP状态变化
  • 3 read/recv返回0的作用
  • 4 SIGPIPE信号

1 TCP连接的11种状态

在TCP建立连接的过程中将经历一系列状态,包括:LISTEN(监听)、SYN-SENT(同步已发送)、SYN-RECEIVED(同步已接收)、ESTABLISHED(已建立)、FIN-WAIT-1(等待第一个关闭)、FIN-WAIT-2(等待第二个关闭)、CLOSE-WAIT(等待关闭)、CLOSING(关闭中)、LAST-ACK(最后的确认)、TIME-WAIT(等待时间)、以及虚构的状态CLOSED(关闭)。

  • CLOSED是虚构的,因为它表示当没有传输控制块(TCB)时的状态(没有连接时的状态)

在TCP标准中:

  • 三次握手:首先发送SYN标志的客户端被称为主动打开者,而另一侧的服务器称为被动打开者
  • 四次挥手:首先发送FIN标志的客户端或服务器被称为主动关闭者,而另一端则被称为被动关闭者

如下图所示:客户端通过发送SYN标志成为SYN_SENT状态的过程(主动打开),同时服务器成为LISTEN状态的过程(被动打开)。

在这里插入图片描述

现在来看一下我们熟悉的三次握手和四次挥手的握手流程:

在这里插入图片描述

  1. LISTEN(监听)
    • 表示服务器在接收到来自客户端的SYN标志后可以创建新连接的状态。
    • 在Linux中,通过bind()listen()系统调用,服务器进入LISTEN状态。
  2. SYN_SENT(SYN已发送)
    • 表示关闭状态的客户端发送SYN标志并转换的状态。
    • 在Linux中,客户端可以通过connect()系统调用进入SYN_SENT状态。
    • 根据/proc/sys/net/ipv4/tcp_syn_retries值以最大RTO(重传超时)间隔发送SYN标志。
  3. SYN_RECEIVED(SYN已接收)
    • 表示处于LISTEN状态的服务器在接收到客户端的SYN标志后,响应SYN+ACK标志并转换的状态。
    • 在Linux中,通过accept()系统调用,服务器进入SYN_RECEIVED状态。
    • 根据/proc/sys/net/ipv4/tcp_synack_retries值以最大RTO(重传超时)间隔发送SYN标志。
  4. ESTABLISHED(已建立)
    • 表示在3次握手后建立连接的状态,服务器和客户端可以交换数据。
    • 在Linux中,通过send()recv()系统调用可以进行数据交换。
    • 可以通过在套接字中设置SO_KEEPALIVE选项来定期检查TCP连接的有效性。
  5. FIN_WAIT_1(等待第一次关闭)
    • 表示在已建立的状态中,主动关闭者结束后转换的状态。主动关闭者在调用close()或其进程终止后,由于套接字关闭,主动关闭者发送FIN标志并进入FIN_WAIT_1状态。
  6. FIN_WAIT_2(等待第二次关闭)
    • 表示FIN_WAIT_1状态的主动关闭者接收到被动关闭者的ACK,或者直到由Linux内核设置的FIN_WAIT_2的超时时间过去为止。
  7. TIME_WAIT(等待时间)
    • 表示FIN_WAIT_2状态的主动关闭者接收到被动关闭者的FIN标志后的状态。TIME_WAIT状态应持续2MSL(2 * 最大分段寿命),即直到网络上的所有相关数据包(分段)完全被清除为止,以确保对后续新连接的影响最小化。
  8. CLOSING(关闭中)
    • 表示发生同时关闭,FIN_WAIT_1状态的主动关闭者接收到FIN标志时的状态。
  9. CLOSE_WAIT(等待关闭)
    • 表示被动关闭者从主动关闭者接收到FIN标志并转换的状态。在Linux环境中,CLOSE_WAIT状态没有超时,只有在被动关闭者的套接字关闭时才会结束。
  10. LAST_ACK(最后确认)
    • 表示CLOSE_WAIT状态的被动关闭者发送FIN标志给主动关闭者后,在收到相应的ACK之前保持的状态。

理论介绍完了,还是得实际写代码看看Linux中这些状态的切换,来看看实际执行过程中会遇到什么问题。

2 实验:查看TCP状态变化

  • 这里实验使用这篇利用fork实现服务端与多个客户端建立连接最后贴出来的代码

1、运行服务端程序

在这里插入图片描述

可以看到此时服务端处于LISTEN状态。

2、运行客户端程序

在这里插入图片描述

现在客户端和服务端都处于ESTABLISHED建立连接状态。

  • SYN_SENTSYN_RCVD状态切换地过快,这里没体现出来

3、关闭客户端程序

在这里插入图片描述

可以看到客户端进入了TIME_WAIT状态。在等待2MSL时间后,客户端的网络状态将关闭(CLOSED)。

3 read/recv返回0的作用

注意:在一端关闭后,另一端需要关闭自己的程序,否则主动关闭的那一端将无法进入TIME_WAIT状态,而是保持在FIN_WAIT2状态。

那如何判断对端关闭了呢? 当一端关闭后,另一端的readrecv函数将无限非阻塞返回0。

现在修改一下服务端的读取代码:
在这里插入图片描述

这里把break注释掉,也就是在客户端关闭时,服务端不退出fork出来的子进程。现在重复一下前面的实验过程:运行服务端和客户端,然后客户端断开连接。如下图所示,客户端果然处于FIN_WAIT2状态。

在这里插入图片描述

所以无论是客户端还是服务端都需要实时的readrecv来判断对端是否断开,进行资源的回收处理,否则对端的状态将无法处于TIME_WAIT

4 SIGPIPE信号

我们知道,当一方关闭连接时,它会发送一个FIN标志给对方。这是TCP的一种半关闭状态,表示发送方(主动关闭的一方)不再发送数据,但仍然可以接收数据。所以当服务端收到客户端发送的FIN后,它可以继续向客户端发送数据,但这些数据会被送入TCP的发送缓冲区,并不会立即发送。

如果客户端收到服务端的FIN并关闭了连接,而服务端仍然试图向客户端发送数据,这时如果客户端已经关闭了接收端,写入操作就会导致Linux内核发送一个SIGPIPE信号被发送给服务端进程。

  • SIGPIPE:用于通知进程它试图向一个已经关闭的管道(或socket)写数据。

默认情况下,如果进程忽略或者不捕获SIGPIPE信号,进程会被终止。因此,为了避免进程因为SIGPIPE信号而终止,可以在程序中捕获SIGPIPE信号,或者在写入之前使用一些手段来检查连接状态。

现在再来修改一下服务端程序:

在这里插入图片描述

这里我们也把break注释掉,这样理论上这个recv函数会无限非阻塞地返回0,也就是服务端用于处理客户端的子进程会一直输出peer closed,同时客户端还会处于FIN_WAIT2状态。就是前面read/recv返回0的作用中的实验结果。

但现在,在服务端的recv返回0时,表示服务端已经收到了FIN信号,此时服务端使用send往客户端发送一个消息。现在会产生一个SIGPIPE信号,将服务端用于处理客户端的子进程杀掉。如下图所示,可以看到进程确实被杀掉了。

在这里插入图片描述

为了验证一下确实产生了SIGPIPE信号,我们自己来注册这个信号。程序做出如下修改:

在这里插入图片描述

结果如下:

在这里插入图片描述

不注册的话,内核默认会将程序杀掉,注册了这个信号的话,内核就不会杀掉进程,就由我们自己处理了。在这里由于服务端的socket_read中没有break掉,内核也没有杀掉这个子进程,所以这里recv将无限非阻塞返回0,加上在这个分支中一直调用send发送数据,所以服务端在这里无限输出peer closed,并无限收到SIGPIPE信号。


所以为了防止服务端程序在客户端被关闭后,由于程序之间没有及时的同步,导致服务端继续往客户端写数据,最后异常地被SIGPIPE信号关闭,我们可以忽略掉SIGPIPE信号以防止服务端被误关闭。

signal(SIGPIPE, SIG_IGN);

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

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

相关文章

水果音乐制作软件FL Studio21.2中文版新功能介绍

FL Studio21.2中文版,一般又称水果音乐制作软件。 FL Studio 21.2简称FL,全称FruityLoopsStudio,因此国人习惯叫它"水果"。它让你的计算机就像是全功能的录音室,大混音盘,非常先进的制作工具,让…

ZYNQ_project:lcd_pic_400x400

在lcd液晶屏上显示400x400像素的图片, 像素信息通过电脑的串口调试助手,发送给fpga,存储在例化的双端口ram中, 在要显示图像区域,读取ram中的像素信息。 模块框图: 时序图: 代码:…

代码随想录刷题】Day16 二叉树03

文章目录 1.【104】二叉树的最大深度(优先掌握递归)1.1 前言1.2 题目描述1.3 递归法java代码实现1.4 迭代法java代码实现1.5 相关练习题【559】N叉树的最大深度 2.【111】二叉树的最小深度(优先掌握递归)2.1 题目描述2.2 递归法ja…

新建模板,或组件自适应

1,***一定要改为固定布局(才可以自适应) 2, 3, 4,系统序号“1”就是第一根柱 5,系列-自动-配色这里1就是第一根柱颜色,2..... 6,坐标柱 标红的去掉,在那里设…

seismicunix基础-声波波动方程推导

seismicunix基础-声波波动方程推导 接触波动方程的研究人员都绕不开这个公式,这是在一维状态下波动方程 但是对于这个方程是怎样来的很少有人能说清楚,其中涉及到牛顿第二运动定律,物体的加速度与受到的力有关。 假设一维弦是大量紧密连接的质…

Python Web框架的三强之争:Flask、Django和FastAPI

JetBrains 公布 2022 Python 开发者调查结果。 完整报告地址:https://lp.jetbrains.com/zh-cn/python-developers-survey-2022/ 这是由 Python 软件基金会 (PSF) 和 JetBrains 共同开展的第六次官方年度 Python 开发者调查,回复于 2022 年 10 月至 12 …

SpringBoot:ch02 配置文件(日志)

前言 简单介绍 Spring Boot 中常见的配置文件类型&#xff0c;如 application.properties 和 application.yml 等&#xff0c;并说明它们各自的特点和用途。 一、前期准备 1、新建项目&#xff0c;结构如下 2、添加依赖 <?xml version"1.0" encoding"UTF…

七、HDFS文件系统的存储原理

1、总结 之所以把总结放在文件开头&#xff0c;是为了让读者对这篇文章有更好的理解&#xff0c;&#xff08;其实是因为我比较懒……&#xff09; 对于整个HDFS文件系统的存储原理&#xff0c;我们可以总结为一句话&#xff0c;那就是&#xff1a; 分块备份 2、存储结构和问题…

智能座舱架构与芯片- (4) 硬件篇 中

2.4 高速视频传输(GMSL) 为了解决未来汽车系统所面临的问题&#xff0c;美信(Maxim)推出了全新下一代GMSL技术&#xff0c;即吉比特多媒体串行链路(GMSL)串行器和解串器&#xff0c;用来支持未来ADAS和信息娱乐系统要求的宽带、互联复杂度和数据完整性的要求。 GMSL技术可以支…

图Graph的存储、图的广度优先搜索和深度优先搜索(待更新)

目录 一、图的两种存储方式 1.邻接矩阵 2.邻接表 生活中处处有图Graph的影子&#xff0c;例如交通图&#xff0c;地图&#xff0c;电路图等&#xff0c;形象的表示点与点之间的联系。 首先简单介绍一下图的概念和类型&#xff1a; 图的的定义&#xff1a;图是由一组顶点和一…

webpack 配置

1、基础配置 // node js核心模塊 const path require(path) // 插件是需要引入使用的 const ESLintPlugin require(eslint-webpack-plugin) // 自动生成index.html const HtmlWebpackPlugin require(html-webpack-plugin); // 将css文件单独打包&#xff0c;在index.html中…

Windows系统如何安装与使用TortoiseSVN客户端,并实现在公网访问本地SVN服务器

文章目录 前言1. TortoiseSVN 客户端下载安装2. 创建检出文件夹3. 创建与提交文件4. 公网访问测试 前言 TortoiseSVN是一个开源的版本控制系统&#xff0c;它与Apache Subversion&#xff08;SVN&#xff09;集成在一起&#xff0c;提供了一个用户友好的界面&#xff0c;方便用…

计算机基础知识56

choices参数的使用 # 应用场景&#xff1a; 学历&#xff1a;小学、初中、高中、本科、硕士、博士、1 2 3 4 5 6 客户来源: 微信渠道、广告、介绍、QQ、等等 性别&#xff1a;男、女、未知 # 对于以上可能被我们列举完的字段我们一般都是选择使用…

【JavaEE】Spring的创建和使用(保姆级手把手图解)

一、创建一个Spring项目 1.1 创建一个Maven项目 1.2 添加 Spring 框架支持 在pom.xml中添加 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.3.RELEASE&…

智能座舱架构与芯片- (15) 测试篇 下

三、持续集成与交付 3.1 自动化编译框架 在智能座舱软件中&#xff0c;分为上层应用软件和底层软件。有些上层应用软件是与指令集平台无关的&#xff0c;例如Java应用程序等&#xff0c;它们对所运行的CPU平台没有依赖性&#xff0c;可以很好的适配当前平台进行执行。而在底层…

IDEA JRebel安装使用教程

1、下载插件 版本列表&#xff1a;https://plugins.jetbrains.com/plugin/4441-jrebel-and-xrebel/versions 下载&#xff1a;JRebel and XRebel 2022.4.1 这里下载2022.4.1版本&#xff0c;因为后续新版本获取凭证会比较麻烦。下载完成会是一个压缩包。 2、安装 选择第一步…

机器学习笔记 - 创建CNN + RNN + CTC损失的模型来识别图像中的文本

我们将创建一个具有CTC损失的卷积循环神经网络来实现我们的OCR识别模型。 一、数据集 我们将使用 Visual Geometry Group 提供的数据。 Visual Geometry Group - University of OxfordComputer Vision group from the University of Oxfordhttps://www.robots.ox.ac.uk/~vgg/d…

离散数学考前小记

数理逻辑 求前束范式的一般步骤&#xff1a; 利用等值公式消去“ → \rightarrow →”和“ ↔ \leftrightarrow ↔”否定深入改名前移量词 仅含有全称量词的前束范式称为SKOLEM标准形。 SKOLEM标准形的求解算法&#xff1a; 先求谓词演算公式的前束范式使用n元函数干掉存在…

Keil MDK 安装

0 Preface/Foreword 1 下载和安装 官网&#xff1a;Keil Embedded Development Tools for Arm, Cortex-M, Cortex-R4, 8051, C166, and 251 processor families. Keil MDK 下载链接&#xff1a;Keil MDK 1.1 下载 根据需求下载对应的Keil MDK edition。 不同的editions包括 …

洛谷 P3252 [JLOI2012] 树

读题就读趋势了&#xff0c;还以为是每个深度都可以选一个&#xff0c;然后深度升序就可以了&#xff0c;以为是个按深度的01背包。 但是前面还说了是一条路径&#xff0c;路径是不能断开的。那就从每个点开始爆搜一次就好了。 看了一下范围n<1e5&#xff0c;n^2爆搜理论上…