Please see the code below:
package main import "net" import "log" import "bufio" import "time" func main() { l,_:=net.Listen("tcp", ":8888") for { conn, _ := l.Accept() log.Println("get conn", conn.RemoteAddr()) go func() { f, _:=conn.(*net.TCPConn).File() d:=f.Fd() log.Println(d) f.Close() arr := make([]byte, 1000) reader := bufio.NewReader(conn) time.AfterFunc(3*time.Second, func() { log.Println("close conn", conn.RemoteAddr()) conn.Close() }) for { size, err := reader.Read(arr) if err != nil { break } log.Println("sss", arr[:size]) } }() } }
when the program start,I use telnet to connect the localhost:8888,after 3 seconds,the server will kill me out, but the socket status is still ESTABLISHED when I use netstat to watch.If I remove the File() function, the socket can be closed normally.How can I fix this?
This is caused by the FDs being put into blocking mode. Once that happens, you're no longer using the runtime network poller, and have to use the socket as if you were using blocking calls and multiple threads. Underneath, a blocking recv
call on a socket can't be interrupted by a close
in another thread.
A workaround may be to force the FD back into non-blocking mode before closing it:
syscall.SetNonblock(int(d), true)
f.Close()
You can also shutdown the socket for reading before calling close:
conn.CloseRead()
conn.Close()