Everything about Http persistent connection, volume for you to see

Everything about Http persistent connection, volume for you to see

[[438351]]

My conclusion from the above is: HTTP Keep-Alive is a sliding renewal and reuse of TCP connections at the application layer. If the client/server renews stably, it becomes a true long connection.

Currently, all Http network libraries have HTTP Keep-Alive enabled by default. Today, we will break down HTTP persistent connections from the perspective of underlying TCP connections and troubleshooting.

"I'm just an ape who writes web programs, why should I know so much??????".

Use the Go language to tinker with an httpServer/httpClient and briefly talk about the usage style of Go.

Use the go language net/http package to quickly build an httpserver and inject a Handler for recording request logs

  1. package main
  2.  
  3. import (
  4. "fmt"  
  5. "log"  
  6. "net/http"  
  7. )
  8.  
  9. // IndexHandler records basic information of the request: Please pay attention to r.RemoteAddr
  10. func Index (w http.ResponseWriter, r *http.Request) {
  11. fmt.Println( "receive a request from:" , r.RemoteAddr, r.Header)
  12. w.Write([]byte( "ok" ))
  13. }
  14.  
  15. // net/http enables persistent connections by default
  16. func main() {
  17. fmt.Printf( "Starting server at port 8081\n" )
  18. if err := http.ListenAndServe( ":8081" , http.HandlerFunc( Index )); err != nil {
  19. log.Fatal(err)
  20. }
  21. }

ListenAndServe creates a default httpServer server. Go controls access permissions by capitalizing the first letter. If the first letter is capitalized, it can be accessed by external packages, similar to C# global functions and static functions.

  1. func ListenAndServe(addr string, handler Handler) error {
  2. server := &Server{Addr: addr, Handler: handler}
  3. return server.ListenAndServe()
  4. }

The net/http server has Keep-Alive enabled by default, which is reflected by the Server's private variable disableKeepAlives.

  1. type Server struct {
  2. ...
  3. disableKeepAlives int32 // accessed atomically.
  4. ...
  5. }

Users can also manually disable Keep-Alive. SetKeepAlivesEnabled() will modify the value of the private variable disableKeepAlives.

  1. s := &http.Server{
  2. Addr: ":8081" ,
  3. Handler: http.HandlerFunc( Index ),
  4. ReadTimeout: 10 * time . Second ,
  5. WriteTimeout: 10 * time . Second ,
  6. MaxHeaderBytes: 1 << 20,
  7. }
  8. s.SetKeepAlivesEnabled( true )
  9. if err := s.ListenAndServe(); err != nil {
  10. log.Fatal(err)
  11. }

The above is also the basic production/usage style of the go language package.

Please note that I inserted IndexHander in httpserver to record the basic information of httpclient.

Here is a point of knowledge: if httpclient establishes a new TCP connection, the system will assign you a random port according to certain rules.

Start the server program and access localhost:8081 in your browser.

The server will receive the following log. The red circle in the figure indicates that the browser uses a random fixed port of the system to establish a TCP connection.

Use net/http to write a client: initiate HTTP requests to the server every 1s

  1. package main
  2.  
  3. import (
  4. "fmt"  
  5. "io/ioutil"  
  6. "log"  
  7. "net/http"  
  8. "time"  
  9. )
  10.  
  11. func main() {
  12. client := &http.Client{
  13. Timeout: 10 * time . Second ,
  14. }
  15. for {
  16. requestWithClose(client)
  17. time .Sleep( time . Second * 1)
  18. }
  19. }
  20.  
  21. func requestWithClose(client *http.Client) {
  22.  
  23. resp, err := client.Get( "http://127.0.0.1:8081" )
  24.  
  25. if err != nil {
  26. fmt.Printf( "error occurred while fetching page, error: %s" , err.Error())
  27. return  
  28. }
  29. defer resp.Body.Close ()
  30.  
  31. c, err := ioutil.ReadAll(resp.Body)
  32. if err != nil {
  33. log.Fatalf( "Couldn't parse response body. %+v" , err)
  34. }
  35.  
  36. fmt.Println(string(c))
  37. }

The request log received by the server is as follows:

The red box in the figure shows that httpclient uses the fixed port 61799 to initiate an http request, and the client/server maintains HTTP Keep-alive.

Use netstat -an | grep 127.0.0.1:8081 to view the system's TCP connection for a specific IP: The client system also establishes only one TCP connection for the server, and the port of the TCP connection is 61799, which corresponds to the above.

Use Wireshark to view the TCP connection of the localhost network card

It can be seen that there is no TCP three-way handshake before each http request/response

After each TCP packet is sent, the other end needs to return an ACK confirmation packet

Negative Example-High Energy Warning

Go's net/http explicitly states:

If the Body is not both read to EOF and closed, the Client's underlying RoundTripper (typically Transport) may not be able to re-use a persistent TCP connection to the server for a subsequent "keep-alive" request.

In other words, if the httpclient client does not read the body or close the body after each request, Keep-alive may fail and goroutine may leak.

  1. // The following code does not read the body, causing Keep-alive to fail
  2. func requestWithClose(client *http.Client) {
  3. resp, err := client.Get( "http://127.0.0.1:8081" )
  4. if err != nil {
  5. fmt.Printf( "error occurred while fetching page, error: %s" , err.Error())
  6. return  
  7. }
  8. defer resp.Body.Close ()
  9. //_, err = ioutil.ReadAll(resp.Body)
  10. fmt.Println( "ok" )
  11. }

The server log is as follows:

The red box in the figure above shows that the client continues to establish TCP connections using new random ports.

View the TCP connection established by the client system:

Wireshark packet capture results:

The red box in the figure shows that three handshakes and four waves occur before and after each HTTP request/response.

Full text

Currently known httpclient and httpServer all enable keep-alive by default

Disabling keep-alive or keeping-alive failing will cause the client and server to frequently establish TCP connections. You can use netstat -an | grep {ip} to view the TCP connections established on the client.

Wireshark captures packets, clarifying the capture effects of keep-alive and non-keep-alive

<<:  The United States has repeatedly stumbled in 5G network construction. What did it do wrong?

>>:  Why 5G Private Networks Are Critical to Enterprise Digital Transformation

Recommend

What is the difference between FTP and SFTP?

In actual project development, the most commonly ...

BuyVM Las Vegas VPS simple test

BuyVM has been shared many times in the blog. It ...

80VPS May Promotion: 800 yuan/month-E3-1230/32GB/1TB/8C (232 IPs) cluster server

80VPS is offering a promotion for some cluster se...

What happens when SDN meets 5G?

SDN is a profound change to traditional IP networ...

What is the difference between LoRa and LoRaWAN?

LoRa, or Long Range, is a proprietary low-power, ...

BGPTO: Singapore dedicated server $49/month, E3-1230v3/16GB/480G SSD/10M (CN2)

BGPTO currently offers a special discount code fo...

User Datagram Protocol (UDP) in plain language

What is UDP? UDP is the abbreviation of User Data...

In the 5G era, how can telecom operators lead the future through IoT services?

Major global telecom operators have been explorin...

Is Matter worth the wait?

An ambitious new smart home networking standard i...

What will the communications network look like in 2030?

[[426987]] This article is reprinted from the WeC...

Common methods of data transmission and data call

With the Internet and the Internet of Things high...

Which collaboration metrics determine the business value of an application?

The criteria for evaluating the business value of...

How 5G standardization will impact future innovation and growth

In 2019, mobile technologies and services contrib...