使用 curl -v 查看 keep alive,服务端没有返回任何 keep-alive 的信息,比较疑惑,于是补充了一下知识。
- $ curl -v http://127.0.0.1:8812 http://127.0.0.1:8812
- * Trying 127.0.0.1...
- * TCP_NODELAY set
- * Connected to 127.0.0.1 (127.0.0.1) port 8812 (#0)
- > GET / HTTP/1.1
- > Host: 127.0.0.1:8812
- > User-Agent: curl/7.64.1
- > Accept: */*
- >
- < HTTP/1.1 200 OK
- < Date: Tue, 31 Dec 2019 03:52:27 GMT
- < Content-Length: 6
- < Content-Type: text/plain; charset=utf-8
- <
- Hello
- * Connection #0 to host 127.0.0.1 left intact
- * Found bundle for host 127.0.0.1: 0x7fda13614800 [can pipeline]
- * Could pipeline, but not asked to!
- * Re-using existing connection! (#0) with host 127.0.0.1
- * Connected to 127.0.0.1 (127.0.0.1) port 8812 (#0)
- > GET / HTTP/1.1
- > Host: 127.0.0.1:8812
- > User-Agent: curl/7.64.1
- > Accept: */*
- >
- < HTTP/1.1 200 OK
- < Date: Tue, 31 Dec 2019 03:52:27 GMT
- < Content-Length: 6
- < Content-Type: text/plain; charset=utf-8
- <
- Hello
- * Connection #0 to host 127.0.0.1 left intact
- * Closing connection 0
- ➜ http-upload-benchmark git:(master)
left intact 意思是 保留不变的,例句:when the nest is upset no egg is left intact [idiom.] — 覆巢之下无完卵
HTTP 协议采用 请求-应答 模式,当使用普通模式,即非 KeepAlive 模式时,每个请求/应答客户和服务器都要新建一个连接,完成之后立即断开连接(HTTP 协议为无连接的协议);当使用 Keep-Alive 模式(又称持久连接、连接重用)时,Keep-Alive 功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive 功能避免了建立或者重新建立连接。来源
在 HTTP 1.0 中, 没有官方的 keepalive 的操作。通常是在现有协议上添加一个指数。如果浏览器支持 keep-alive,它会在请求的包头中添加:
- > Connection: Keep-Alive
-
然后当服务器收到请求,作出回应的时候,它也添加一个头在响应中:
- > Connection: Keep-Alive
-
这样做,连接就不会中断,而是保持连接。当客户端发送另一个请求时,它会使用同一个连接。这一直继续到客户端或服务器端认为会话已经结束,其中一方中断连接。
在 HTTP 1.1 中 所有的连接默认都是持续连接,除非特殊声明不支持。HTTP 持久连接不使用独立的 keepalive 信息,而是仅仅允许多个请求使用单个连接。
按照这个思路,我做了一下验证:
HTTP/1.0,果然发完,服务端主动关闭连接了
- $ telnet 127.0.0.1 8812
- Trying 127.0.0.1...
- Connected to localhost.
- Escape character is '^]'.
- GET / HTTP/1.0
- Host: 127.0.0.1:8812
-
- HTTP/1.0 200 OK
- Date: Tue, 31 Dec 2019 03:59:34 GMT
- Content-Length: 6
- Content-Type: text/plain; charset=utf-8
-
- Hello
- Connection closed by foreign host.
- $
HTTP/1.0,加上 Connection: Keep-Alive,服务器端没关闭连接
- http-upload-benchmark git:(master) telnet 127.0.0.1 8812
- Trying 127.0.0.1...
- Connected to localhost.
- Escape character is '^]'.
- GET / HTTP/1.0
- Host: 127.0.0.1:8812
- Connection: Keep-Alive
-
- HTTP/1.0 200 OK
- Date: Tue, 31 Dec 2019 04:00:38 GMT
- Content-Length: 6
- Content-Type: text/plain; charset=utf-8
- Connection: keep-alive
-
- Hello
- GET / HTTP/1.0
- Host: 127.0.0.1:8812
-
- HTTP/1.0 200 OK
- Date: Tue, 31 Dec 2019 04:00:48 GMT
- Content-Length: 6
- Content-Type: text/plain; charset=utf-8
-
- Hello
- Connection closed by foreign host.
- ➜ http-upload-benchmark git:(master)
HTTP/1.1,默认连接保持了
- ➜ http-upload-benchmark git:(master) telnet 127.0.0.1 8812
- Trying 127.0.0.1...
- Connected to localhost.
- Escape character is '^]'.
- GET / HTTP/1.1
- Host: 127.0.0.1:8812
-
- HTTP/1.1 200 OK
- Date: Tue, 31 Dec 2019 04:02:11 GMT
- Content-Length: 6
- Content-Type: text/plain; charset=utf-8
-
- Hello
- GET / HTTP/1.1
- Host: 127.0.0.1:8812
-
- HTTP/1.1 200 OK
- Date: Tue, 31 Dec 2019 04:02:12 GMT
- Content-Length: 6
- Content-Type: text/plain; charset=utf-8
-
- Hello
- ^[
- HTTP/1.1 400 Bad Request
- Content-Type: text/plain; charset=utf-8
- Connection: close
-
- 400 Bad RequestConnection closed by foreign host.
通过 netstat 查看端口监听情况
- $ netstat -an | grep 8812
- tcp4 0 0 127.0.0.1.8812 127.0.0.1.52493 ESTABLISHED
- tcp4 0 0 127.0.0.1.52493 127.0.0.1.8812 ESTABLISHED
- tcp46 0 0 *.8812 *.* LISTEN
服务端可以这么告知客户端:Keep-Alive: timeout=15, max=100 15 秒内还可以再发 100 个请求,然后就会关闭连接了。
- $ sudo tcpdump -i lo0 -s 0 -n tcp -c 1000 -w /tmp/p1.pcap
-
- tcpdump: listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
- 1000 packets captured
- 1032 packets received by filter
- 0 packets dropped by kernel
- ➜ ~
再用 wireshark 打开 p1.pcap,指定过滤条件 tcp.port == 8087,过滤 src 或 dst port 是 8087 的,就是我们感兴趣的tcp包
go-http-client 关闭 keep-alive 再抓包试试:
- $ go-http-client -sleep 1s -keepalive=false
- 2019/12/31 13:18:46 server http://127.0.1:8812
- 2019/12/31 13:18:46 sleep 1s
- 2019/12/31 13:18:46 keepalive false
- 2019/12/31 13:18:46 retry mode false
- 2019/12/31 13:18:46 dumpResponse HTTP/1.1 200 OK
- Connection: close
- Content-Length: 6
- Content-Type: text/plain; charset=utf-8
- Date: Tue, 31 Dec 2019 05:18:46 GMT
-
- Hello
- 2019/12/31 13:18:46 start sleep 1s
- 2019/12/31 13:18:47 dumpResponse HTTP/1.1 200 OK
- Connection: close
- Content-Length: 6
- Content-Type: text/plain; charset=utf-8
- Date: Tue, 31 Dec 2019 05:18:47 GMT
-
- Hello
从图中,就可以看出每次都是从头三次握手。