HTTP 连接详解

news2024/10/5 13:15:23

概述

世界上几乎所有的 HTTP 通信都是由 TCP/IP 承载的,客户端可以打开一条TCP/IP连接,连接到任何地方的服务器。一旦连接建立,客户端和服务器之间交换的报文就永远不会丢失、受损或失序

TCP(Transmission Control Protocol)传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。通俗来讲,TCP就是双方通信的一个规范标准,负责对数据的传输进行一定的控制

HTTP 要传送一条报文时,会以流的形式将报文数据的内容通过一条打开的 TCP 连接按序传输。TCP 收到数据流之后,会将数据流分成被称作段的小数据块,并将段封装在 IP 分组中,通过因特网进行传输。所有这些工作都是由 TCP/IP 软件来处理的、HTTP 程序员什么都看不到

每个 TCP 段都是由 IP 分组承载,从一个 IP 地址发送到另一个 IP 地址,每个 IP 分组包括:

  • IP 分组首部(通常为 20 字节)
  • TCP 段首部(通常为 20 字节)
  • TCP 数据块(0 个或多个字节)

IP 首部包含了源和目的 IP 地址、长度和其他一些标记。TCP 段的首部包含了 TCP 端口号、TCP 控制标记,以及用于数据排序和完整性检查的一些数字值

TCP 段首部格式如下:

  • 源端口号就是指本地端口,目的端口号就是远程端口

  • 序号,也称序列号(Sequence Number),用于 TCP 通信过程中某一传输方向上字节流的每个字节的编号,以防止乱序问题。简单来说,就是在传输过程中用序列号来标记自己的位置,保证数据能按序传输

  • 确认序号,也称确认序列号(Acknowledgment Numbe),是接收确认端所期望收到的下一序列号。确认序号应当是上次已成功收到数据字节序号加 1,只有当标志位中的 ACK 标志为 1 时该确认序列号的字段才有效。主要用来解决不丢包的问题

  • 标志位,TCP Flag,TCP 首部中有 6 个标志比特,它们中的多个可同时被设置为 1,主要是用于操控 TCP 的状态机,依次为 URG,ACK,PSH,RST,SYN,FIN

    • ACK

      表示应答域有效,这个标识可以理解为发送端发送数据到接收端,发送的时候 ACK 为 0,标识接收端还未应答,一旦接收端接收数据之后,就将 ACK 置为 1,发送端接收到之后,就知道了接收端已经接收了数据

    • SYN

      表示同步序列号,用来建立 TCP 连接。SYN 标志位和 ACK 标志位搭配使用,当连接请求的时候,SYN = 1,ACK = 0;连接被响应的时候,SYN = 1,ACK = 1;这个标志的数据包经常被用来进行端口扫描。扫描者发送一个只有 SYN 的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口

    • FIN

      表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送 FIN 标志位的 TCP 数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描

  • 窗口大小(Window Size),也称为滑动窗口大小,用来进行流量控制


TCP 三次握手

TCP 三次握手,即建立 TCP 连接,需要客户端和服务端总共发送 3 个包以确认连接的建立。在 Socket 编程中,这一过程由客户端执行 connect 来触发

TCP 握手的目的有三个:

  • 确认双方的接收与发送能力是否正常
  • 初始化序列号,为后面的可靠传送做准备
  • 进行数字证书的验证以及加密密钥的生成

  • 第一次握手:客户端发送请求报文将 SYN = 1 同步序列号和初始化序列号 seq = J 发送给服务端,发送完之后客户端处于发送等待状态
  • 第二次握手:服务端受到 SYN 请求报文之后,如果同意连接,会以自己的同步序列号 SYN = 1、初始化序列号 seq = K 和确认序列号(期望下次收到的数据包)ack = J + 1 以及确认号 ACK = 1 报文作为应答,此时服务器为确认接收状态
  • 第三次握手:客户端接收到服务端的 SYN + ACK 之后,知道可以发送下一序列的数据包了,然后发送同步序列号 ack = K + 1 和数据包的序列号 seq = J + 1 以及确认号 ACK = 1 确认包作为应答,客户端转为确认连接状态

为什么是三次握手,而不是一次、二次呢?因为有可能出现这种情况:客户端发送了一个连接请求,但出现网络延迟,导致客户端没有及时收到服务端的响应,就会认为本次请求失效。而这时原本延迟的请求又来到服务端,服务端确认并保持等待状态,但实际上此时客户端并没有与服务端连接的意思,这就会导致服务器一直处于等待状态,造成资源浪费


TCP 四次挥手

TCP 四次挥手,即终止 TCP 连接,需要客户端和服务端总共发送 4 个包以确认连接的断开。在 Socket 编程中,这一过程由客户端或服务端任一方执行 close 来触发

  • 第一次分手:第一次分手无论是客户端还是服务端都可以发起,因为 TCP 是全双工的。假如客户端发送的数据已经发送完毕,发送 FIN = 1 告诉服务端,客户端所有数据已经全发完了,服务端可以关闭接收了,但如果服务端还有数据要发给客户端,客户端照样可以接收的。此时客户端处于 FIN_WAIT_1 等待关闭状态
  • 第二次分手:服务端接收到客户端的释放请求连接之后,知道客户端没有数据要发给自己了,然后服务端发送 ACK = 1 告诉客户端已经收到发给自己的信息,此时服务端处于 CLOSE_WAIT 等待关闭状态
  • 第三次分手:此时服务端已经没有数据向客户端发送了,然后发送一个 FIN = 1,用于告诉客户端,服务端的所有数据发送完毕,客户端可以关闭接收数据连接了。此时服务端状态处于 LAST_ACK 确认关闭状态
  • 第四次分手:此时如果客户端收到了服务端发送完的信息之后,就发送 ACK = 1,告诉服务端,客户端已经收到了服务端的信息,服务端处于 CLOSED 状态,四次挥手全部完成

为什么是四次挥手呢?因为关闭连接时,己方收到对方的 FIN 报文,仅仅表示对方不再向自己发送数据,但还能接受数据。己方可能还有数据要发送给对方,所以不能向三次握手一样直接把 ACK 和 SYN 放一起发送,而是先发送 ACK,直到没有数据要发送了,才是 FIN 确认关闭连接


TCP 性能优化

HTTP 位于 TCP 上层,所以 HTTP 事务的性能在很大程度上取决于底层 TCP 通道的性能

1. 延迟确认

为了避免网络延迟导致的数据丢失,TCP 实现了自己的确认机制来确保数据的成功传输

每个 TCP 段都有一个序列号和数据完整性校验和。每个段的接收者收到完好的段时,都会向发送者回送小的确认分组。如果发送者没有在指定的窗口时间内收到确认信息,发送者就认为分组已被破坏或损毁,并重发数据

由于确认报文很小,所以 TCP 允许将返回的确认信息与输出的数据分组结合在一起,更有效地利用网络。为了增加确认报文找到同向传输数据分组的可能性,TCP 实现了一种【延迟确认】算法,延迟确认算法会在一个特定的窗口时间(通常是 100-200 毫秒)内将输出确认存放在缓冲区中,以寻找能够捎带它的输出数据分组。如果在那个时间段内没有输出数据分组,就将确认信息放在单独的分组中传送

2. TCP 慢启动

TCP 数据传输的性能还取决于 TCP 连接的使用期,TCP 连接会随着时间进行自我调节,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度,这种调节被称为 TCP 慢启动,用于防止因特网的突然过载和拥塞

TCP 慢启动限制了一个 TCP 端点在任意时刻可以传输的分组数。简单来说,每成功接收一个分组,发送端就有了发送另外两个分组的权限。如果某个 HTTP 事务有大量数据要发送,是不能一次将所有分组都发送出去的,必须发送一个分组,等待确认,然后发送两个分组,每个分组都必须被确认,然后发送四个分组,以此类推,这种方式被称为【打开拥塞窗口】

由于存在这种拥塞控制特性,所以新连接的传输速度会比已经交换过一定量数据的连接慢一些

3. Nagle 算法与 TCP_NODELAY

TCP 有一个数据流接口,应用程序可以通过它将任意尺寸的数据放入 TCP 栈中,即使一次只放一个字节。但是,每个 TCP 段都至少装载了40个字节的标记和首部如果 TCP 发送了大量包含少量数据的分组,网络的性能就会严重下降

Nagle 算法试图在发送一个分组之前,将大量 TCP 数据绑定在一起,以提高网络效率。Nagle 算法鼓励发送全尺寸的分组,只有当所有其他分组都被确认之后,Nagle 算法才允许发送非全尺寸的分组。如果其他分组仍然在传输过程中,就将那部分数据缓存起来。只有当挂起分组被确认,或者缓存中积累了足够发送一个全尺寸分组的数据时,才会将缓存的数据发送出去

Nagle 算法会引发几种 HTTP 性能问题,首先,小的 HTTP 报文可能无法填满一个分组,可能会因为等待那些永远不会到来的额外数据而产生时延。其次,Nagle 算法与延迟确认之间的交互存在问题,Nagle 算法会阻止数据的发送,直到有确认分组抵达为止,但确认分组自身会被延迟确认算法延迟 100-200 毫秒

HTTP应用程序常常会禁用 Nagle 算法,如果要使用的话,一定要确保会向TCP写入大块的数据,不会产生一堆小分组

4. TIME_WAIT 累积与端口耗尽

当某个 TCP 端点关闭 TCP 连接时,会在内存中维护一个小的控制块,用来记录最近所关闲连接的 IP 地址和端口号。这类信息只会维持一小段时间,通常是所估计的最大分段使用期的两倍(称为 2MSL,通常为两分钟左右),以确保在这段时间内不会创建具有相同地址和端口号的新连接

2MSL 的连接关闭延迟在某些情况下会出现问题,例如客户端每次连接到服务器时,都会获得一个新的端口,以实现连接的唯一性,但由于可用端口的数量有限(比如 60000 个),而且在 2MSL 秒(比如 120 秒)内连接是无法重用的,连接率就被限制在 60000/120=500 次/秒,如果服务器的连接率高于 500 次/秒,就会遇到端口耗尽问题


HTTP 连接处理

1. 串行事务处理延时

如果只对连接进行简单的管理,TCP 的性能时延可能会叠加起来。比如,假设有一个包含了三个嵌入图片的 Web 页面,测览器需要发起四个 HTTP 事务来显示此页面:一个用于顶层的 HTML 页面,三个用于嵌入的图片。如果每个事务都需要建立一条新的连接,那么连接时延和慢启动时证就会叠加起来

除了串行加载引入的实际时延之外,加载一幅图片时,页面上其他地方都没有动静也会让人觉得速度很慢,用户更希望能够同时加载多幅图片。并行加载的另一个缺点是,有些沟览器在对象加载完毕之前无法获知对象的尺寸,而它们可能需要尺寸信息来决定将对象放在屏幕的什么位置,所以在加载了足够多的对象之前,无法在屏靠上显示任何内容

2. 并行连接

HTTP 允许客户端打开多条连接,并行地执行多个 HTTP 事务,提高加载速度,但并不是绝对的,在带宽较小的情况下,并行执行多个 HTTP 事务带来的性能提升就很小,甚至没什么提升。而且,打开大量连接会消耗大量的资源

3. 持久连接

Web 客户端经常会打开到同一个站点的连接,比如,一个 Web 页面上的大部分内嵌图片通常都来自同一个 Web 站点。因此,对某服务器 HTTP 请求的应用程序很可能会在不久的将来发起更多的请求。因此,HTTP/1.1 允许 HTTP 设备在事务处理结束之后会将 TCP 连接保持在打开状态,以便在未来重用现存的连接发起 HTTP 请求,称为持久连接,直到客户端或服务器决定将其关闭为止。持久连接可以避免缓慢的连接建立阶段,以及慢启动的拥塞适应阶段,以便更快速地进行数据传输。通常情况下,持久连接和并行连接配合使用

实现 HTTP/1.0 的客户端可以通过包含 Connection:Keep-Alive 首部请求将一条连接保持在打开状态,如果服务器愿意为下一条请求将连接保持在打开状态,就在响应中包含相同的首部。如果响应中没有 Connection:Keep-Alive 首部,客户端就认为服务器不支特 Keep-alive,会在收到响应报文之后关闭连接

可以用 Keep-A1ive 通用首部中指定的,由逗号分隔的选项来调节 keep-alive 的行为

Connection: Keep-Alive
Keep-Alive: max=5, timeout=120
  • timeout:估计服务器希望将连接保持在活跃状态的时间,这并不是一个承诺值
  • max:估计服务器还希望为多少个事务保持此连接的活跃状态,这并不是一个承诺值

HTTP/1.1 逐渐停止对 keep-alive 连接的支持,用一种名为持久连接(persistentconnection)的改进型设计取代了它。,HTTP/1.1 默认所有连接都是持久的,要在事务处理结束之后关闭连接,必须向报文中显式地添加一个 Connection: close 首部。客户端收到响应后,除非响应中包含 connection: close 首部,否则连接就维持在打开状态。但是,客户端和服务端仍然可以随时关闭空闲的连接,不发送 connection: close 并不意味着服务端承诺永远将连接保持在打开状态

4. 管道化连接

HTTP/1.1 允许在持久连接上可选的使用管道,在响应到达之前,可以将多条请求放入队列,当第一条请求到达服务器,第二条和第三条请求也可以开始发送了。在高时延网络条件下,这样可以降低网络的环回时间,提高性能

对管道化连接有几点注意事项:

  • 如果 HTTP 客户端无法确认连接是持久的,就不应该使用管道
  • 必须按照与请求相同的顺序回送 HTTP 响应,HTTP 报文中没有序列号标签,如果收到的响应失序了,就没办法将其与请求匹配起来了
  • HTTP 客户端必须做好连接会在任意时刻关闭的准备,还要准备好重发所有未完成的管道化请求。如果客户端打开了一条持久连接,并立即发出了十条请求,服务器可能只处理了五条请求之后关闭连接,客户端必须能够应对过早关闭连接的情况,重新发送请求
  • HTTP 客户端不应该用管道化的方式发送会产生副作用的请求(比如 POST),如果出错,管道化方式会阻碍客户端了解服务器执行的是一系列管道化请求中的哪一个

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

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

相关文章

【大数据】HDFS、HBase操作教程(含指令和JAVA API)

目录 1.前言 2.HDFS 2.1.指令操作 2.2.JAVA API 3.HBase 3.1.指令操作 3.2.JAVA API 1.前言 本文是作者大数据专栏系列的其中一篇,前文中已经详细聊过分布式文件系统HDFS和分布式数据库HBase了,本文将会是它们的实操讲解。 HDFS相关前文&#x…

商家转账到零钱怎么开通?一步步教你玩转微信营销新利器

在数字化营销日新月异的今天,微信支付凭借其便捷、安全的特点,成为了商家不可或缺的支付工具。而其中的“商家转账到零钱”功能,更是为商家提供了一个全新的营销利器。今天,我们就来详细解读一下如何开通这一功能(我处…

强化学习在一致性模型中的应用与实验验证

在人工智能领域,文本到图像的生成任务一直是研究的热点。近年来,扩散模型和一致性模型因其在图像生成中的卓越性能而受到广泛关注。然而,这些模型在生成速度和微调灵活性上存在局限。为了解决这些问题,康奈尔大学的研究团队提出了…

从0开始学python(七)

目录 前言 1 break、continue和pass函数 1.1 break 1.2 continue 1.3 pass 2、序列的索引及切片操作 2.1字符串的索引和切片 2.1.1 字符串索引 2.1.2 字符串切片 总结 前言 上一篇文章我们介绍了python中的循环结构,包括for和while的使用。本章接着往下讲。…

springboot+layuimini实现树形表格

树形表格实现增删改查 这里写目录标题 效果图前端页面代码前端插件后端代码controllerserviceserviceImpl 实现类Entitymapperxml mybatis代码数据表 效果图 前端页面代码 <!DOCTYPE html> <html lang"en" xmlns:th"http://www.thymeleaf.org"&g…

java项目之企业OA管理系统源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的企业OA管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 企业OA管理系统的主要使用…

CCPD车牌检测识别数据集

CCPD 是一个在开源免费的中国城市车牌识别数据集。 1. 介绍 CCPD (Chinese City Parking Dataset, ECCV)是中国城市车牌数据集&#xff0c;共有两个CCPD2019和CCPD2020 数据集&#xff0c;总数据量约35W左右&#xff0c;可用于车牌检测和识别模型算法开发。 CCPD 发表的论文:…

体验GM CHM Reader Pro,享受高效阅读

还在为CHM文档的阅读而烦恼吗&#xff1f;试试GM CHM Reader Pro for Mac吧&#xff01;它拥有强大的功能和出色的性能&#xff0c;能够让你轻松打开和阅读CHM文件&#xff0c;享受高效、舒适的阅读体验。无论是学习、工作还是娱乐&#xff0c;GM CHM Reader Pro都能成为你的得…

(java)websocket服务的两种实现方式

1.基于java注解实现websocket服务器端 1.1需要的类 1.1.1服务终端类 用java注解来监听连接ServerEndpoint、连接成功OnOpen、连接失败OnClose、收到消息等状态OnMessage 1.1.2配置类 把spring中的ServerEndpointExporter对象注入进来 2.1代码示例 2.1.1 maven配置 <…

字节码基础

基本概念 java中的字节码&#xff0c;英文bytecode。是java代码编译后的中间代码格式。JVM需要读取并解析字节码才能执行相应的任务。java字节码是JVM的指令集。JVM加载字节码格式的class文件。校验之后通过JIT编译器转换成本机机器代码执行。 java字节码简介 1、java byteco…

MySQL 身份认证漏洞 CVE-2012-2122

漏洞影响版本 MariaDB versions from 5.1.62, 5.2.12, 5.3.6, 5.5.23 are not.MySQL versions from 5.1.63, 5.5.24, 5.6.6 are not.演示 开启靶场 进入漏洞目录 cd /root/vulhub/mysql/CVE-2012-2122开启漏洞靶场 docker-compose up -d攻击 直接 运行 这个命令 for i i…

基于SSM+Vue的物流管理系统

运行截图 获取方式 Gitee仓库

Linux开发--Linux内核开发移植

Linux内核开发移植 Linux内核版本变迁及其获得 Linux是最受欢迎的自由电脑操作系统内核&#xff0c; 是一个用C语言写成&#xff0c; 并且符合POSIX标准的类Unix操作系统 Linux是由芬兰黑客Linus Torvalds开发的&#xff0c; 目的是尝试在英特尔x86架构上提供自由免费的类Un…

旅游推荐管理系统(小组项目)

文章目录 前言 一、项目介绍 1. 项目目的 2. 项目意义 2.1 提升旅游体验 2.2 促进旅游业发展 2.3 数据积累与分析 2.4 提升服务品质 2.5 优化资源配置 二、项目结构 1. 主要使用的技术 1.1 若依&#xff08;Ruoyi&#xff09;框架 1.2 Vue.js框架 1.3 Ajax 1.4 …

RS2227XN功能和参数介绍及PDF资料

RS2227XN是一款模拟开关/多路复用器 品牌: RUNIC(润石) 封装: MSOP-10 描述: USB2.0高速模拟开关 开关电路: 双刀双掷(DPDT) 通道数: 2 工作电压: 1.8V~5.5V 导通电阻(RonVCC): 10Ω 功能&#xff1a;模拟开关/多路复用器 USB2.0高速模拟开关 工作电压范围&#xff1a;1.8V ~ 5…

leetcode刷题指南

本文我将分享给大家一套我自己使用良久并觉得非常高效的 学习论&#xff0c;它可以运用到 Leetcode 上的刷题&#xff0c;也可以 generalize 到生活中涉及到学习以及记忆的方方面面。当然&#xff0c;本文将以 Leetcode 刷题为 case study 去进行讲解。 更具体一点, 我会教大家…

WEB后端复习——JSP、EL、JSTL

JSP:Java Serve Pages(Java服务器页面) 运行在服务器的脚本、在静态网页HTML代码中嵌入java 优势特点 1.被编译后可以多次直接运行&#xff0c;代码执行效率高&#xff08;一次加载、多次可用&#xff09; 2.动态代码封装&#xff0c;组件可重用性高&#xff08;JavaBean EJ…

Linux安装配置CGAL,OpenCV和Gurobi记录

安装Qt&#xff0c;查看当前的Qt版本&#xff0c;需要至少满足v5.12 qmake -v安装CGAL&#xff0c;The Computational Geometry Algorithms Library (cgal.org) CGAL v5.6.1&#xff1a;https://github.com/CGAL/cgal/releases/download/v5.6.1/CGAL-5.6.1.tar.xz 确保C编译…

图鸟UI vue3:基于Vue3和UniApp的酷炫简洁UI框架

引言 随着前端技术的不断发展&#xff0c;开发效率和用户体验成为了前端开发中的两大关键因素。为了提高开发效率和提供更好的用户体验&#xff0c;各种UI框架应运而生。其中&#xff0c;TuniaoUI作为一款基于Vue3和UniApp开发的UI组件库&#xff0c;以其酷炫简洁的设计和丰富…

厉害了!12秒将百万数据通过EasyExcel导入MySQL数据库中

一、写在开头 我们在上一篇文章中提到了通过EasyExcel处理Mysql百万数据的导入功能&#xff08;一键看原文&#xff09;&#xff0c;当时我们经过测试数据的反复测验&#xff0c;100万条放在excel中的数据&#xff0c;4个字段的情况下&#xff0c;导入数据库&#xff0c;平均耗…