2
votes

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?

1
Never ignore errors. For example code at minimum do if err != nil {log.Fatal(err)}. You make everyone looking at your code wonder if there is some error from Listen or Accept (or Close) or File() that is just being ignored.Dave C
Can you use defer f.Close() just on the next line after you open the file?Pie 'Oh' Pah
@DaveC ok,you're very cautiousvzex

1 Answers

8
votes

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()