TCPConn SetWriteDeadline无法正常工作

I'm writing a TCP client in Golang. The server will never send any replies, or any data.

As soon as I fail to write after a given timeout I want the client to close the connection.

So from reading the documentation for SetWriteDeadline in Conn: https://golang.org/pkg/net/#Conn

    // SetWriteDeadline sets the deadline for future Write calls
    // and any currently-blocked Write call.
    // Even if write times out, it may return n > 0, indicating that
    // some of the data was successfully written.
    // A zero value for t means Write will not time out.
    SetWriteDeadline(t time.Time) error

From the above description I use it like this:

...
for {
    select {
    case msg := <-messages:
        conn.SetWriteDeadline(time.Now().Add(1 * time.Second))

        // When server goes away this just blocks forever. No timeout!
        n, err := conn.Write(msg.ByteArray())
        if err != nil {
            return err
        }
        log.Printf("Sent %v bytes
", n)
    }
}
...

But the timeout is never triggered if the server goes away, instead the Write call will just block forever.

  • What am I doing wrong with SetWriteDeadline?
  • I want to kill the connection if the Write does not finish within the given timeout no matter what, if SetWriteDeadline is not the proper way to do that, how do I do it?

This turned out to be a deadlock issue.

My program was using a lock each time it was sending on the messages channel using the Fanout pattern.

The problem was that when I was returning the err on the Write timeout there was a defer call that attempted to lock that same Mutex. Since I did not get the output I was expecting I thought the timeout never triggered.

defer func() {
    thing.ThatCreatedDeadlock()
    log.Println("Expected to see this")
}

So simply logging on the Write error directly would have made this obvious:

    n, err := conn.Write(msg.ByteArray())
    if err != nil {
        log.Println(err)
        return err
    }