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

2019-01-10 17:33:00 +08:00
 asilin

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

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

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

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

可见,http1.1 的队首阻塞发生在服务器端。
q397064399
2019-01-10 17:48:12 +08:00
看了一下 没错的话 应该是请求一股脑子全过去,然后服务器根据请求的顺序 然后一股脑子写回来,不过这样对应用 API 处理有很大的问题,有可能多个请求在同一个 tcp 连接下,然后第一请求 遇到一个较长阻塞的慢 SQL 查询 直接拖慢了整体的请求返回时间
goofool
2019-01-10 17:54:18 +08:00
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
2019-01-10 17:59:44 +08:00
这就是 http 能流行的因素之一,简单,99%的应用都能凑活着用
zhujinliang
2019-01-10 18:45:08 +08:00
HTTP1.0 时代规定了一次 HTTP 请求的过程是:建立 TCP 链接,发送请求头,发送请求 body,服务器返回响应头,返回 body 数据,断开 TCP 链接。请求头和响应头都是文本,以两次换行为结束标志,判断数据发送结束更简单粗暴,TCP 链接断开了就是数据发送完了。
HTTP1.1 协议进行了扩充,要求如果打算复用链接( Keep-Alive ),传送数据时要么响应头指定 Content-Length,要么用 chunked 编码,这两种方法都可以判断一次请求的数据发送完成。在一次请求结束之后,TCP 链接才可被复用进行下一次请求,否则根本无法判断当前传送的数据属于哪次请求的。
毕竟 HTTP1.1 还是基于纯文本的协议,无法做出“管道”的概念,如果在 TCP 链接之上再建一层“管道”逻辑,每个请求在各自的管道中进行,管道间互不影响,才能做到在一个 TCP 链接上并发处理请求。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/525759

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX