The day before yesterday, there was a miraculous error in the process of the call, the error in the client side of the http request error Get "http://127.0.0.1:8800": EOF
, but the server side does not have any exception all the logs are normal execution
Since the error is only on the client side, the Google search results are not caused by the actual scenario (there is no suspicion that there is a problem on the server side), so we have no choice but to capture the packets, and finally the problem is solved
Reason
Server.Server write timeout is set to 10s, so by the time the handler finishes processing the request, the connection between the server and the client is already closed.
However, since the data written on the server side is much smaller than the write buffer size (4096 byte) set in the http/net package, the Write method of bufio does not return an error
Catching packets
source code: https://github.com/yakumioto/demo-response-write-timeout
Since the test environment is too complicated, I wrote a demo to reproduce the whole process, the following is the wireshark exported svc which can be seen:
- the client establishes a TCP connection with the server through three handshakes
- the client sends a normal HTTP request
- the normal Keep-Alive period is maintained
- the server disconnected from the client with four handshakes
|
|
Source Code Analysis
Since it’s a source code analysis that follows from the beginning!!!
Entry method, for easy location tracking of source code
|
|
Here are some important variables to document, which will be covered later in the source code
b.bufr
: conn’s read buffer b.bufw
: conn’s write buffer, 4096 byte in size c.readRequest(ctx)
: the req request is processed, and a *response
is returned ServeHTTP(w, w.req)
: eventually w is passed all the way down all the way down, to our own processing function
Now let’s see how this w
is generated
|
|
Writer is the equivalent of calling w.w.Write(p []byte) == w.cw.Write(p []byte) w.cw
: which is of type chunkWriter so if the call to w.w.Write(p []byte) == chunkWriter.Write([]byte)
|
|
cw.res.conn
: According to the above code, we find that conn == w.conn == srv.newConn(rw) cw.res.conn.bufw
: that is c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4 “10), which shows that the buffer for conn write is 4096 byte
bufio
: if the length of the data does not exceed len(b.buf), the data will be copied to b.buf, and not actually written to b.wr
|
|