net.Accept question

Hi,
I’m trying to understand the behavior of net.Accept, it turns out that golang program is accepting new connections even if the goroutine that executed net.Accept is blocked. Here is
the example.

package main

import (
        "log"
        "net"
        "time"
)

func main() {
        ln, err := net.Listen("tcp", ":8080")
        if err != nil {
                log.Fatal(err)
        }

        for {
                conn, err := ln.Accept()
                if err != nil {
                        log.Println("Conn error: ", err)
                }

                go handleConn(conn)
                time.Sleep(10 * time.Minute)
        }

}

func handleConn(conn net.Conn) {
        conn.Write([]byte("Bye bye\n"))
        conn.Close()
}

Even that goroutine is sleeping I can make new connections and send data, the connections with the sent data will be processed later when goroutine will wake up.

It looks like something else is accepting connections for us.
I know that sleeping or blocking there make sense in just some cases (like limiting connections to our program) but I would like to understand why it is working like this. The same thing done in C will cause the new connection to fail and this is what I would expect because I’m not accepting any new connections.

1 Like

@tmw, what is “ln” here?

ln is the return of net.Listen function, in this case, it is a tcp network listener that is accepting connections on port 8080.

ln.Accept() is in the for {} loop and not inside the goroutine you start on go handleConn(conn). That will start a new goroutine for every cycle of the for loop. Is that not what you want?

You should probably also add a continue inside the error handling there so that you do not start a goroutine if there is an error, but skip to the next cycle instead.

Edit:

I completely missed the 10 minute sleep. I’m not sure what you are doing on your end (do you have another version of this running still? A process might be stuck).

For me this will say “Bye bye” to the first connection, and the second connection will not work until the 10 minute sleep is done.

maybe that port is busy. did u tried changing port number?

Yes, it will do that, it will say “Bye bye” to the first connection and then it will not work until 10-minute sleep. My question is why I can connect other clients within this 10-minute window? I can connect and send data even that I do not accept any connections.
This scenario written in C will cause the new connections to break because we are not accepting new connections for 10 minutes, we are sleeping.

1 Like

because Accept has a queue in system, if you don’t accept the connection, system will save for you!

Well, sure there is a queue where sockets wait for being accepted but when we do not execute accept the system will not accept it for us. The other thing is that we will not be able to send data to connections that were not accepted.
From the accept(2)

The accept() system call is used with connection-based socket types
       (SOCK_STREAM, SOCK_SEQPACKET).  It extracts the first connection
       request on the queue of pending connections for the listening socket,
       sockfd, creates a new connected socket, and returns a new file
       descriptor referring to that socket.

Write the code that I posted in C and you will see the difference.

It looks like something in Golang is accepting new connections (netpoller ?) even that we do not Accept them.
I was surprised looking at this, normally when you do not accept connection it will be not accepted :slight_smile:.

It seems that in golang everything will be accepted and it will accept an unlimited amount of data send to the socket without our knowledge/permission.
If this is the way golang wants it to be then fine, I was just surprised and did not find anything about this in the documentation.

Ok, it was my misunderstanding.
The behavior of Golang and C program is the same, the difference was backlog parameter in C, it was too low and that is the reason why new connections go to SYN_RECV and finally were dropped. In Golang the backlog parameter is set to 128 and it could handle more connections in the pending connection’s queue.

So in summary, if we sleep like in my example the number of connections requests will be accepted (ESTABLISHED state) up to backlog limit (128 in golang example). If the queue is full then the new connections will go into SYN_RECV state and if accept will not take any of the pending connection from the queue the connections in SYN_RECV will fail.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.