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", n)
}
}
...
But the timeout is never triggered if the server goes away, instead the Write
call will just block forever.
SetWriteDeadline
? 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
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.