• 请不要在回答技术问题时复制粘贴 AI 生成的内容
asilin
V2EX  ›  程序员

HTTP 长连接/持久链接中,必须等待上一个请求的回应数据完全接收后,才能开启下一次请求么?

  •  
  •   asilin · Jan 10, 2019 · 4532 views
  •   You need to sign in to view this topic
    This topic created in 2824 days ago, the information mentioned may be changed or developed.

    今天在写一个 python web 服务时,突然想到如果 HTTP 长连接只管发送请求,不等回应,那怎么判断返回的数据属于哪一次的请求呢?

    进而想到,只有上一次的请求的回应数据完全接收后(根据 Content-Length 头部),才能进行下一次的请求。 也就是说,长连接实际上是一个阻塞 loop,所以才需要有“连接池”的存在,不断的创建新的 TCP 链接,来实现请求的并发。

    为了验证自己的想法,在看 urllib3 的部分代码。

    Supplement 1  ·  Jan 10, 2019

    服务端“队首阻塞”的概念,确实解决了请求排队等待的问题!

    由这个问题,也想到了为什么网络上有那么多“TCP 粘包”的问题了。
    因为 HTTP 1.0/1.1 协议使用了简单的纯文本来通信,而不是二进制,导致了很多人就认为 HTTP 就是 "TCP + 纯文本",进而想到需要如何解决边界定位问题,也就是所谓的“粘包”

    由此可见,HTTP 2.0 才是正常的 ISO 七层协议的实现,增加了第六层表示层
    如果一开始就接触 HTTP 2.0,也就不会有所谓的“粘包”问题了,因为TCP发送数据时,数据本身就是结构化数据,实现了自我的边界定位!

    7 replies  •  2019-01-10 18:45:08 +08:00
    q397064399
        1
    q397064399  
       Jan 10, 2019
    HTTP2 解决了这个问题
    q397064399
        3
    q397064399  
       Jan 10, 2019
    对于同一个 tcp 连接,http1.1 允许一次发送多个 http1.1 请求,也就是说,不必等前一个响应收到,就可以发送下一个请求,这样就解决了 http1.0 的客户端的队首阻塞。但是,http1.1 规定,服务器端的响应的发送要根据请求被接收的顺序排队,也就是说,先接收到的请求的响应也要先发送。这样造成的问题是,如果最先收到的请求的处理时间长的话,响应生成也慢,就会阻塞已经生成了的响应的发送。也会造成队首阻塞。

    可见,http1.1 的队首阻塞发生在服务器端。
    q397064399
        4
    q397064399  
       Jan 10, 2019
    看了一下 没错的话 应该是请求一股脑子全过去,然后服务器根据请求的顺序 然后一股脑子写回来,不过这样对应用 API 处理有很大的问题,有可能多个请求在同一个 tcp 连接下,然后第一请求 遇到一个较长阻塞的慢 SQL 查询 直接拖慢了整体的请求返回时间
    goofool
        5
    goofool  
       Jan 10, 2019
    https://tools.ietf.org/html/rfc2068#section-8.1

    A client that supports persistent connections MAY "pipeline" its
    requests (i.e., send multiple requests without waiting for each
    response). A server MUST send its responses to those requests in the
    same order that the requests were received.
    hilbertz
        6
    hilbertz  
       Jan 10, 2019
    这就是 http 能流行的因素之一,简单,99%的应用都能凑活着用
    zhujinliang
        7
    zhujinliang  
       Jan 10, 2019
    HTTP1.0 时代规定了一次 HTTP 请求的过程是:建立 TCP 链接,发送请求头,发送请求 body,服务器返回响应头,返回 body 数据,断开 TCP 链接。请求头和响应头都是文本,以两次换行为结束标志,判断数据发送结束更简单粗暴,TCP 链接断开了就是数据发送完了。
    HTTP1.1 协议进行了扩充,要求如果打算复用链接( Keep-Alive ),传送数据时要么响应头指定 Content-Length,要么用 chunked 编码,这两种方法都可以判断一次请求的数据发送完成。在一次请求结束之后,TCP 链接才可被复用进行下一次请求,否则根本无法判断当前传送的数据属于哪次请求的。
    毕竟 HTTP1.1 还是基于纯文本的协议,无法做出“管道”的概念,如果在 TCP 链接之上再建一层“管道”逻辑,每个请求在各自的管道中进行,管道间互不影响,才能做到在一个 TCP 链接上并发处理请求。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2183 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 54ms · UTC 10:28 · PVG 18:28 · LAX 03:28 · JFK 06:28
    ♥ Do have faith in what you're doing.