Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i interrupt a goroutine executing (*TCPListener) Accept?

Tags:

go

I am playing with go lately and trying to make some server which responds to clients on a tcp connection.

My question is how do i cleanly shutdown the server and interrupt the go-routine which is currently "blocked" in the following call

func (*TCPListener) Accept?

According to the documentation of Accept

Accept implements the Accept method in the Listener interface; it waits for the next call and returns a generic Conn.

The errors are also very scarcely documented.

like image 849
mhstnsc Avatar asked Sep 16 '13 09:09

mhstnsc


3 Answers

Here is what i was looking for. Maybe helps someone in the future. Notice the use of select and the "c" channel to combine it with the exit channel

    ln, err := net.Listen("tcp", ":8080")
    if err != nil {
        // handle error
    }
    defer ln.Close()
    for {
        type accepted struct {
            conn net.Conn
            err  error
        }
        c := make(chan accepted, 1)
        go func() {
            conn, err := ln.Accept()
            c <- accepted{conn, err}
        }()
        select {
        case a := <-c:
            if a.err != nil {
                // handle error
                continue
            }
            go handleConnection(a.conn)
        case e := <-ev:
            // handle event
            return
        }
    }
like image 99
mhstnsc Avatar answered Oct 07 '22 07:10

mhstnsc


Simply Close() the net.Listener you get from the net.Listen(...) call and return from the executing goroutine.

like image 25
thwd Avatar answered Oct 07 '22 07:10

thwd


TCPListener Deadline

You don't necessarily need an extra go routine (that keeps accepting), simply specify a Deadline.

for example:

for {

    // Check if someone wants to interrupt accepting
    select {
    case <- someoneWantsToEndMe: 
        return // runs into "defer listener.Close()"
    default: // nothing to do
    }

    // Accept with Deadline
    listener.SetDeadline(time.Now().Add(1 * time.Second)
    conn, err := listener.Accept()
    if err != nil {
        // TODO: Could do some err checking (to be sure it is a timeout), but for brevity
        continue
    }

    go handleConnection(conn)
}
like image 45
Levite Avatar answered Oct 07 '22 06:10

Levite