After we build a TCP server, and we read the bytes from the connection established by client (e.g. HTTP server), we can get error something like this: read tcp [::1]:9090->[::1]:49232: read: connection reset by peer
. In the example, the TCP server is running on port 9090
, and there was several clients connecting to the TCP server. What does the error msg mean?
Basically it means that the connection that was once established by client is now close abruptly by the client (the client can be down, thus closing the connection right away in client side). Client sends the RST packet (read: Reset packet) telling that this connection is not going to send any more data.
Example in Go
TCP server
package main
import (
"bufio"
"fmt"
"io"
"log"
"net"
)
const (
TCPPort = 9090
)
func main() {
log.Printf("start TCP server at port: %v", TCPPort)
listener, err := net.Listen("tcp", fmt.Sprintf(":%v", TCPPort))
if err != nil {
log.Panicf("error in listening, err: %v", err)
}
log.Printf("listener: %+v", listener)
defer func() {
if err := listener.Close(); err != nil {
log.Panicf("error in closing listener")
}
log.Printf("success in closing listener")
}()
for {
conn, err := listener.Accept()
if err != nil {
log.Panicf("error in accepting connection, err: %v", err)
}
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
for {
buf := make([]byte, 4096)
_, err := bufio.NewReader(conn).Read(buf)
if err != nil {
if err == io.EOF {
log.Printf("EOF")
break
}
log.Panicf("error in reading buffer, err: %v", err)
}
msg := fmt.Sprintf("message received, string: %s\n", string(buf))
conn.Write([]byte(msg))
}
conn.Close()
}
HTTP server
package main
import (
"bufio"
"fmt"
"log"
"net/http"
)
const (
HTTPPort = 8080
)
func loginHandler(w http.ResponseWriter, r *http.Request) {
conn := pool.Get()
defer func() {
pool.Put(conn)
}()
_, err := conn.Write([]byte("hello I am dicky"))
if err != nil {
log.Panicf("error in writing into connection, err: %v", err)
}
buf := make([]byte, 4000)
_, err = bufio.NewReader(conn).Read(buf)
if err != nil {
log.Panicf("error in reading string from connection, err: %v", err)
}
}
func main() {
log.Printf("HTTP server starting at port %v", HTTPPort)
http.HandleFunc("/login", loginHandler)
InitConnPool(100)
err := http.ListenAndServe(fmt.Sprintf(":%v", HTTPPort), nil)
if err != nil {
log.Fatalf("error in listening and serving http server, err: %v", err)
}
log.Println("finished serving HTTP server")
}
Connection Pool
I built connection pool in HTTP server side. Why? Because creating new connection in every coming request is expensive.
package main
import (
"log"
"net"
)
type ConnectionPool struct {
connPool chan net.Conn
}
func (c *ConnectionPool) Get() net.Conn {
return <-c.connPool
}
func (c *ConnectionPool) Put(conn net.Conn) {
c.connPool <- conn
}
var pool *ConnectionPool
func InitConnPool(n int) {
pool = &ConnectionPool{
connPool: make(chan net.Conn, n),
}
for i := 0; i < n; i++ {
conn, err := net.Dial("tcp", "localhost:9090")
if err != nil {
log.Panicf("error in dialing in conn pool, err: %v", err)
}
pool.connPool <- conn
}
}
Steps to reproduce connection reset by peer
- Start TCP server
$ go run tcp_server/main.go
2022/05/16 07:22:03 start TCP server at port: 9090
- Start HTTP server
$ go run ./http_server/
2022/05/16 07:20:47 HTTP server starting at port 8080
- Send request to HTTP API endpoint
/login
:
curl localhost:8080/login
- Stop the HTTP server Press ctrl + c / cmd + c (in mac)
Result: Since I start with n num of connections to TCP server, some of them will return EOF, except 1 that will return TCP: connection reset by peer
...
2022/05/16 07:24:17 EOF
2022/05/16 07:24:17 EOF
2022/05/16 07:24:17 EOF
2022/05/16 07:24:17 error in reading buffer, err: read tcp [::1]:9090->[::1]:50312: read: connection reset by peer
panic: error in reading buffer, err: read tcp [::1]:9090->[::1]:50312: read: connection reset by peer
goroutine 6 [running]:
log.Panicf({0x10f59a1?, 0xc0001c7000?}, {0xc000059ef0?, 0x1?, 0x1?})
/usr/local/go/src/log/log.go:392 +0x67
main.handleConnection({0x11174d0, 0xc000010030})
/Users/dickynovanto/Documents/Go/http_tcp/tcp_server/main.go:55 +0x2ef
created by main.main
/Users/dickynovanto/Documents/Go/http_tcp/tcp_server/main.go:37 +0x14f
exit status 2