使用poll()实现HTTP持久连接的连接复用问题求助
问题分析与解决
你的HTTP持久连接无法被curl复用,核心原因是服务器返回的响应缺少明确的结束标志,导致curl只能通过关闭连接来判断响应完成,进而无法复用连接。
从curl的输出日志可以看到关键提示:
* no chunk, no close, no size. Assume close to signal end
这说明你的响应既没有指定Content-Length头,也没有使用分块编码(Transfer-Encoding: chunked),curl无法确定响应体何时结束,只能默认等待连接关闭来确认响应完成,因此会主动关闭连接#0,重新建立连接发送第二个请求。
而谷歌的响应里包含了Content-Length: 219,curl读完对应长度的内容后,就知道响应结束,会保持连接打开,等待下一个请求。
解决方案
1. 给HTTP响应添加Content-Length头
计算响应体的字节长度,在响应头里明确声明,示例如下:
HTTP/1.1 200 OK Connection: keep-alive Keep-Alive: timeout=2, max=100 Content-Length: 27 <html> Hello, world! </html>
这里Content-Length的值是响应体(<html>...Hello, world!...<html>)的字节数,你需要根据实际内容计算准确值。
2. 或使用分块编码(Transfer-Encoding: chunked)
如果响应体长度无法提前计算,可使用分块编码,格式如下:
HTTP/1.1 200 OK Connection: keep-alive Keep-Alive: timeout=2, max=100 Transfer-Encoding: chunked 1b <html> Hello, world! </html> 0
其中1b是十六进制表示的响应体字节数(对应十进制27),最后一行0表示分块结束。
3. 确保服务器循环逻辑正确
你的poll循环逻辑本身没问题,处理完一次请求后,会回到poll等待下一个请求。但要注意:
- 处理
recv()时要完整读取客户端的请求数据(HTTP请求是有格式的,需要读到请求结束标志) - 发送响应后不要关闭
sockfd,保持连接打开
修改后的测试效果
添加Content-Length后,curl的输出会变成类似谷歌的情况:
curl -v localhost:4390 localhost:4390 * Trying 127.0.0.1:4390... * Connected to localhost (127.0.0.1) port 4390 (#0) > GET / HTTP/1.1 > Host: localhost:4390 > User-Agent: curl/7.81.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Connection: keep-alive < Keep-Alive: timeout=2, max=100 < Content-Length: 27 < <html> Hello, world! </html> * Connection #0 to host localhost left intact * Re-using existing connection! (#0) with host localhost > GET / HTTP/1.1 > Host: localhost:4390 > User-Agent: curl/7.81.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Connection: keep-alive < Keep-Alive: timeout=2, max=100 < Content-Length: 27 < <html> Hello, world! </html> * Connection #0 to host localhost left intact
内容的提问来源于stack exchange,提问作者Artyom Gevorgyan
相关产品推荐
相关产品推荐

