网络编程(10) : 从connect到三次握手建立连接,再从close到四次挥手断开连接

news2024/9/25 23:23:34

1、TCP前置知识

1.1什么是TCP

  • TCP 是面向连接的可靠的基于字节流的传输层通信协议。
    • 面向连接:必须是一对一建立连接后才能通信
    • 可靠的:无论网络链路出现怎么样的变化,TCP可以保证报文一定能被对端收到
    • 字节流流式协议,不带边界属性,接收端无法直接确认一组有效的用户信息,且TCP报文是有序的

UPD和TCP的区别

  • TCP要面向连接,UDP不需要连接,即刻传输数据
  • TCP是一对一服务,UDP支持一对一,一对多,多对多的交互通信
  • TCP有拥塞控制、流量控制保证数据传输安全,UDP没有拥塞控制,不限流,即使网络拥堵,也不会影响UDP的发送速率
  • TCP流式协议,没有边界,但保证顺序和可靠,UDP是一个包一个包发的,有边界,但是会丢包和乱序
  • UDP实时性好,适用于游戏领域,TCP延迟ACK

1.2、TCP状态图

在这里插入图片描述

  • 三次握手状态:
    • CLOSED:关闭状态,一般在四次挥手之后的状态
    • SYN_SENT: 返送连接请求后,表示已经发送连接请求
    • ESATABLISHED: 客户端收到SYN+ACK、或者服务端收到ACK后,表示已经建立TCP连接,可以开始通信了
    • SYN_RECV: 服务端收到客户端的SYN连接请求后,此时需要向客户端也发起连接请求并响应回复SYN+ACK
    • LISTEN: 服务端开启侦听之后,可以接收客户端发起的连接请求
  • 四次挥手状态:
    • FIN_WAIT1: 客户端发送FIN报文之后,客户端状态
    • CLOSE_WAIT: 服务器接收FIN报文之后,服务器状态
    • FIN_WAIT2: 客户端接收服务器对FIN报文的应答之后客户端状态
    • TIME_WAIT: 客户端接收到服务器FIN报文且做出应答ACK之后,客户端状态
    • LAST_ACK: 服务器发送FIN报文后,服务器状态
    • CLOSED: 服务器接收到客户端ACK报文后的状态,客户端TIEM_WAIT结束后的状态

1.3 TCP报文格式

在这里插入图片描述

  • 源端口和目标端口就是从哪个应用发给哪个应用(断开用于标识应用)
  • 序号seq: 用于标识TCP发送出去的字节流,解决包乱序
  • 确认号ack:对已收到包进行确认,ack=seq+1,解决丢包问题
  • 标志为:SYN发起连接、ACK回复确认应答、RSTTCP连接出现异常需要强制断开、FIN表示后面不再发送数据,希望断开连接、URG紧急指针有效、PSH接收方应该尽快将这个报文交给引用层,TCP是面向连接的,双方通过TCP报文修改各自的TCP状态
  • 窗口大小:通信双方要标识窗口大小,表示当前自己能接收多少数据,用于流量控制

2、从connect到三次握手

2.1、从connect到三次握手建立连接

在这里插入图片描述

  • 一开始客户端和服务端都处于CLOSED状态。
  • 服务端先要开启侦听,TCP状态从CLOSED变成LISTEN ,可以开始接收连接进行三次挥手

    开启侦听流程: int listenfd = socket() -> bind(listenfd,ip+port) -> listen(listenfd,backlog)

  • 第一次握手:客户端connect()系统调用之后,从用户态切换到内核态,TCP协议栈组织三次握手包,向服务器发送SYN报文连接,客户端从CLOSED状态进入SYN_SENT
  • 第二次握手:服务器收到SYN连接,并返回客户端ACK+SYN回复请求并也发起连接,服务器TCP状态从LISTEN转变到SYN_RECV,在这里会有一个半连接队列(SYN队列),存放着当前客户端和服务器的TCP连接
  • 第三次握手:客户端收到ACK+SYN,并对服务器报文返回ACK,客户端TCP状态从SYN_SENT转变为ESATABLISHED,服务器接收到ACK,TCP状态从SYN_RECV转变为ESATABLISHED,三次握手连接建立完成,服务器这里有个全连接队列(accept队列),将半连接队列中的TCP连接节点加入到全连接队列
  • 客户端处于ESATABLISHED时,connect返回0 表示连接成功,服务器处于ESATABLISHED时,accept全连接队列中取出一个TCP连接节点,并给这个连接节点分配一个clientfd用于和客户端通信

2.2 TIP:

  • accept发生在三次握手完成后,TCP连接节点在全连接队列,accept全连接队列中取出一个TCP连接节点,并给这个连接节点分配一个clientfd用于和客户端通信;

  • listen函数的第二个参数backlog=半连接队列数+全连接队列数,

  • listenbind为什么要单独设计? 接口越单一,后续的可调度性和可重复利用的概率越高

  • bind为什么绑定ip? 一台机器一般有多个网卡,一个网卡对应一个ip

  • 每次标志位携带ACK,就是对接收报文的应答,对应的确认号ack为接收到报文的序列号seq+1,表示自己已经就受到报文

  • 第一次握手丢失:

    • 服务器没有对SYN报文进行应答(可能是服务器没有收到),客户端会进行5-6次SYN(每次重传的seq是一样的),每隔一段时间进行尝试一次,直到超时返回-1,errno为ETIMEOUT,connect连接建立失败
  • 第二次握手丢失:

    • 客户端没有收到ACK,会觉得第一次握手丢失,重传SYN
    • 客户端不会对服务器的SYN+ACK报文进行应答,服务端收不到三次握手,服务端也会每隔一段重发SYN+ACK(重复五次),并且等待一段时间(SYN Timeout)之后丢弃这个没有完成的连接(断开连接)
  • 第三次握手丢失:

    • 客户端发起第三次握手,进入ESATABLISHED状态
    • 服务端接受不到第三次握手,会触发重传机制,直到收到第三次握手,或者是超时断开连接
    • 就算第三次握手的ACK丢掉了,只要客户端发送数据,服务器就会进入ESATABLISHED状态, 因为数据包中的ack和第三次握手的ack相同都是对第二次握手的确认
  • SYN Flood攻击: 大量客户端没有回应ack导致 半连接队列中的TCP连接溢出, 后续建立连接的请求会被内核丢弃

  • 如果避免SYN Flood攻击

    • 增大TCP半连接队列;
    • 开启tcp_syncookies:可以在不使用syn半连接队列的情况下成功建立连接,当syn半连接队列满了之后,后续的SYN包不会丢失,会根据算法计算出一个cookie值,cookie值会放到第二次握手的报文里面,服务器在收到ACK的时候会检查包的合法性,如果合法就放到accept全连接队列中
    • 减少SYN+ACK重传次数:加快断开处于SYN_RECV状态的TCP连接
  • 前两次握手不可以携带数据,第三次握手可以携带数据,因为客户端握手后,就进入了ESATABLISHED状态

  • 为什么是三次握手:

    • 为了防止旧的重复连接初始化造成混乱,客户端泵机,网络拥塞,导致第一个SYN报文没有送到, 客户端重启会重传SYN报文,但是拥塞的SYN报文会先到,而每次SYN报文序列号不一样,服务端对旧 SYN回复SYN+ACK, 客户端会直接回复RST, 服务端收到RST会释放旧连接,客户端只会对新的SYN+ACK报文进行ACK, 服务端收到ACK双方连接建立成功
    • 为什么两次握手无法解决历史SYN问题,服务端对旧连接的建立会浪费资源:如果服务端在一次握手的时候进入ESATABLISHED状态,说明连接建立(分配socket文件句柄), 服务端可以对客户端收发数据,但是服务端不知道这个是历史连接,在收到客户端会回复的RST前,服务端可以发送数据,从而导致资源浪费, 服务端收到RST才知道是历史连接从而断开连接(释放sock文件句柄,资源浪费),如果多次由于网络阻塞导致的历史SYN, 会导致服务器资源严重浪费
    • 三次握手可以保证双方序列号同步,服务端ACK确认客户端序列号,客户端ACK确认服务端序列号,而序列号可以保证TCP传输有序性的关键
    • 三次握手就可以建立可靠的连接,四次握手没有必要

2、从close到四次挥手

2.1 前置关于close和shutdown

  • close
    • 减少socket文件描述符的引用,当引用为0的时候,就会关闭连接(socket读写通道,并触发四次挥手发送FIN报文),收回socket文件句柄
  • shutdown
    • 可以只关闭socket读通道(SHUT_RD),或者只关闭写通道(SHUT_WR),或者同时关闭读写通道(SHUT_RDWR),调用完shutdown之后还需要调用close关闭socket文件句柄,但是shutdown没有资源计数的概念,会直接影响所有的sockfd
    • shutdown(sd, SHUT_WR)关闭socket写通道,触发四次挥手,发送FIN报文给对端,告诉对端我不再发数据了,但是可以读;
    • shutdown(sd, SHUT_RD):关闭socket读通道,TCP协议栈不给对端发送网络消息,本端进入read操作会返回错误
    • shutdown(sd, SHUT_RDWR): 同时关闭读写通道,也会触发四次挥手,TCP发送FIN报文

2.2 从close到四次挥手断开连接

四次挥手的客户端和服务器是相对的,先断开连接,谁就是客户端
在这里插入图片描述

  • 前提socket文件描述符的引用只有1,客户端close, 关闭连接, 回收句柄资源,触发TCP四次挥手
  • 第一次挥手:客户端调用close触发四次挥手,TCP协议栈发送FIN报文, 告诉服务端没有数据要发了,客户端进入FIN_WAIT1状态,等待服务端应答
  • 第二次挥手:服务端接收到客户端的FIN报文,向客户端发送ACK报文应答,进入CLOSE_WAIT状态,TCP协议栈会给FIN报文插入EOF文件结束符,触发读事件,服务器read的时候会返回0,从而知道对端关闭连接,客户端收到ACK报文,进入FIN_WAIT2状态,等待服务端第三次挥手(FIN报文)
  • 第三次挥手:服务器调用close(),也组织FIN报文发给客户端,服务器进入LAST_ACK等待客户端的最后的挥手ACK
  • 第四次握手:客户端收到服务器的FIN报文,发送最后挥手应答ACK,进入TIME_WAIT状态,服务器接收到ACK进入到CLOSED状态,服务端已经完成连接关闭,客户端需要等待2MSL进入CLOSED状态,这样客户端也完成连接关闭

2.3 TIP

  • ACK是TCP协议栈回复出去的,close是应用程序调用的,close的调用权在应用层

  • 为什么要四次挥手:

    • 客户端向服务器发送FIN报文,表示的是不在发送但是还可以接收数据
    • 服务器回复ACK之后可能还需要处理数据和发送,等服务器不需要发送的时候,才给客户端发送FIN指令,表示同意关关闭连接
    • 由于服务端可能还需要等待处理没有完成的数据,以至于服务端回复的ACKFIN是分开的,因此需要四次挥手
  • 四次挥手可以是三次嘛?:

    • close粗暴关闭:客户端读写对端全部关闭,服务端发送发ACK之后,还想发送数据,客户端协议栈会发送RST报文,服务器会直接关闭连接
    • shutdown优雅关闭:会经历完整的四次挥手,只关闭写,不关闭读,服务器在CLOSE_WAIT状态还是可以给对端发送数据的,客户端收到了会回复ACK, 当服务器数据处理完成没有要发的,就会调用close关闭连接挥手资源,发送FIN报文
    • TCP延迟确认机制(默认开启)会导致第二次握手和第三次握手合并,从而出现三次握手
  • 第一次挥手丢失:

    • 第一次挥手客户端向服务器发送FIN报文,并进入FIN_WAIT1状态,如果客户端收不到服务器的第二次挥手ACK, 客户端会重传FIN报文,每隔一段事件重传一次,超时没有收到ACK,客户端直接进入CLOSED状态
  • 第二次挥手丢失:

    • 服务器发送ACK, 进入CLOSE_WAIT状态,服务器发送的ACK丢失, 客户端收不到ACK会每隔段不停重传FIN,超时客户端直接进入CLOSED状态
  • 第三次挥手丢失:

    • 对于服务器而言:
      • 服务器发送FIN,进入LAST_ACK, FIN丢失,服务器收不到ACK, 服务器就会重发,超时断开连接
    • 对于客户端而言:
      • close状态下:客户端收到ACK之后进入FIN_WAIT2状态,这个状态只会维持60s, 超时没有等到服务器的FIN, 客户端直接关闭连接进入CLOSED状态
      • shutdown只关闭写通道状态下:还是可以读数据的,客户端会一直处于FIN_WAIT2状态死等服务器的FIN报文
  • 第四次挥手丢失:

    • 客户端发送ACK,进入TIME_WAIT状态, 如果服务器没有收到ACK, 依旧处于LAST_ACK状态,会重发FIN报文,如果四次挥手一直丢失,则服务器超过重传次数,就会直接关闭连接进入CLOSED状态,客户端在维持TIME_WAIT状态消失后也会进入CLOSED状态
    • 客户端的TIME_WAIT状态就是为了防止ACK丢失
  • TIME_WAIT状态:

    • 处于TIME_WAIT的客户端每次收到FIN指令都会重新发送ACK并重新计时
    • 可以确保服务端,正确的关闭,也就是防止ACK丢失
    • 防止旧连接数据,被新连接接收,新旧连接在相同端口
    • 缺点: 资源被占用、端口被占用
  • 出现大量close_wait

    • CLOSE_WAIT处于服务端返送完ACK之后到close之前,主要问题是没有及时close,可能是由于业务逻辑写的不对,close前面存在耗时操作
  • 出现大量TIME_WAIT

    • 服务端主动断开很多TCP连接才会出现大量TIME_WAIT
    • 一般出现在,大量HTTP短链接,服务器主动断开连接

参考文章:

https://xiaolincoding.com/network/3_tcp/tcp_interview.html#tcp-%E5%A4%B4%E6%A0%BC%E5%BC%8F%E6%9C%89%E5%93%AA%E4%BA%9B

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

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

相关文章

QGraphicsView实现简易地图1『加载离线瓦片地图』

最简单粗暴的加载方式,将每一层级的所有瓦片地图全部加载 注:该方式仅能够在瓦片地图层级较低时使用,否则卡顿!!! 瓦片地图数据来源:水经注-高德地图-卫星地图 瓦片地图瓦片大小:25…

损失函数篇 | YOLOv8 更换损失函数之 MPDIoU | 《2023 一种用于高效准确的边界框回归的损失函数》

论文地址:https://arxiv.org/pdf/2307.07662v1.pdf 边界框回归(Bounding Box Regression,BBR)在目标检测和实例分割中得到了广泛应用,是目标定位的重要步骤。然而,对于边界框回归的大多数现有损失函数来说,当预测的边界框与真值边界框具有相同的长宽比,但宽度和高度的…

想学Python高级编程?必须了解这个小技巧:match-case!

大家好,这里是程序员晚枫,小破站/知乎/小红书/抖音都叫这个名字。 上次给大家分享了Python高级编程第一讲:从使用类型提示开始 ;今天分享Python高级编程第二讲:深入解析Python中switch case的使用方法。 写在前面 分…

Python时间处理:探索time模块

日常工作中,经常涉及到一些时间的转换操作,比如某些业务针对时间的操作要转成不同的时区,有的要转换格式入库,有的需要跟时间对比等等,接下来我们一起来看一下python里面是怎么去处理时间的。 time模块简单介绍 Python…

C语言实现扫雷游戏

test.c源文件 - 扫雷游戏测试 game.h头文件 - 扫雷游戏函数的声明 game.c源文件 - 扫雷游戏函数的实现 1.布置雷 -- 存放雷的雷盘 9*9 数组设计成11*11 上下左右方各多一行,保证周围8的范围 雷 - 1 不是雷 - 0 2.排查雷 主题测试源文件代码 &…

MySQL基础扎实——如何优化DISTINCT

在优化 MySQL 中的 DISTINCT 查询时,以下是一些常见的方法和技巧: 索引优化:为涉及 DISTINCT 的列创建索引。索引可以加速列值的查找和比较,以提高查询性能。请注意,在表中存在大量重复值的情况下,索引可能…

[个人笔记] vCenter设置时区和NTP同步

VMware虚拟化 - 运维篇 第三章 vCenter设置时区和NTP同步 VMware虚拟化 - 运维篇系列文章回顾vCenter设置时区和NTP同步(附加)ESXi设置alias参考链接 系列文章回顾 第一章 vCenter给虚机添加RDM磁盘 第二章 vCenter回收活跃虚拟机的剩余可用空间 vCente…

JavaEE——文件操作和IO

文章目录 一、认识什么是文件二、Java对文件的操作三、文件内容读写——数据流1. 对字节流中的读操作解释2.对字节流中写操作解释3.解释 input 、output 和 closs() 方法4. Scanner 在文件中的使用 四、简单使用代码操作文件 一、认识什么是文件 狭义的文件: 指的是…

Web博客项目及jwt的学习

这几天完善了发布博客,完成了收藏博客的功能 博客项目 一共有三种身份: 访客(未登录),用户,管理员。 其中管理员拥有的功能最多,其次是用户,然后是访客。 从功能上看&#xff1a…

Java面向对象编程实战详解(图书管理系统示例)

文章目录 面向编程概念图书管理系统示例需求分析设计阶段编码实现创建目录结构Book类的编码BookList类的编码User类的编码AdminUser类的编码NormalUser类的编码启动类的编写具体的操作实现IOperation接口新增图书的实现借阅图书的实现删除图书的实现显示图书的实现查找图书的实…

51单片机双机通信

对于这个51单片机双机通信,之前无聊做的玩的,但是既然写了一篇51单片机串行口通信的博客,那就顺便出来供大家学习,希望能够帮助到一些刚刚接触51单片机的朋友。废话不多讲,直接上正题。 1、实习任务 1.1 任务目的 通…

AIGC人工智能辅助开发:提升效率、优化代码、实现智能编程

文章目录 1. 什么是AIGC人工智能辅助开发?2. AIGC的优势和应用场景2.1 提升开发效率2.2 优化代码质量2.3 实现智能编程 3. 如何用好AIGC人工智能辅助开发?3.1 选择合适的AIGC工具3.2 理解AIGC的工作原理3.3 逐步应用AIGC辅助开发3.4 主动参与AIGC的学习和…

Raki的读paper小记:RWKV: Reinventing RNNs for the Transformer Era

Abstract&Introduction&Related Work 研究任务 基础模型架构已有方法和相关工作 RNN,CNN,Transformer稀疏注意力(Beltagy等人,2020年;Kitaev等人,2020年;Guo等人,2022年&am…

组合模式——树形结构的处理

1、简介 1.1、概述 树形结构在软件中随处可见,例如操作系统中的目录结构、应用软件中的菜单、办公系统中的公司组织结构等。如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题。组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形…

Flowable-中间事件-补偿中间抛出事件

定义 补偿中间抛出事件用于触发一个补偿,当执行到达补偿中间抛出事件时触发该流程已完成活动 的边界补偿事件(Compensate Boundary Interrputing Event),完成补偿操作后自动执行后继路线。 图形标记 补偿中间抛出事件显示为普通…

【elasticsearch系】1.初识玩转elasticSearch

首先给大家介绍下我使用的版本是7.17.3这个版本,关于之前6.x的版本还是有些区别的。 elasticSearch Elasticsearch 是一个分布式文档存储。Elasticsearch 不是将信息存储为列式数据行,而是存储已序列化为 JSON 文档的复杂数据结构。存储文档时&#xff0…

PHP8的数据类型-PHP8知识详解

在PHP8中,变量不需要事先声明,赋值即声明。 不同的数据类型其实就是所储存数据的不同种类。在PHP8.0、8.1中都有所增加。以下是PHP8的15种数据类型: 1、字符串(String):用于存储文本数据,可以使…

【深度学习】High-Resolution Image Synthesis with Latent Diffusion Models,论文

13 Apr 2022 论文:https://arxiv.org/abs/2112.10752 代码:https://github.com/CompVis/latent-diffusion 文章目录 PS基本概念运作原理 AbstractIntroductionRelated WorkMethodPerceptual Image CompressionLatent Diffusion Models Conditioning Mec…

【13】STM32·HAL库-正点原子SYSTEM文件夹 | SysTick工作原理、寄存器介绍 | printf函数使用、重定向

目录 1.sys文件夹介绍(掌握)2.deley文件夹介绍(掌握)2.1deley文件夹函数简介2.2SysTick工作原理2.3SysTick寄存器介绍2.4delay_init()函数(F1)2.5delay_us()函数(F1)2.6delay_ms()函…

网络安全-防御需知

目录 网络安全-防御 1.网络安全常识及术语 资产 漏洞 0day 1day 后门 exploit APT 2.什么会出现网络安全问题? 网络环境的开放性 协议栈自身的脆弱性 操作系统自身的漏洞 人为原因 客观原因 硬件原因 缓冲区溢出攻击 缓冲区溢出攻击原理 其他攻击…