I want to send a file through TCP in golang. here's my server code:
c is connected *net.TCPConn
file, _ := os.Open(fn)
defer file.Close()
io.Copy(c, file)
// c.CloseWrite()
and client:
as above, c is connected *net.TCPConn
file, _ := os.Create("file.txt")
defer file.Close()
io.Copy(file, c)
my question is: in this way, the client can not receive the EOF of the file
so, io.Copy
blocked. I have to call c.CloseWrite
to notify client that the file is over.
If I want to send files, this will not work, How can I solve this?
If you are using a TCP connection, then os.EOF error means that the connection closed by the other end.
I think the only way to reliably send a file would be to implement a multi-state protocol.
Eg. At the first state of the transfer, tell the client how much bytes to read and go to state 2. In state 2, if all bytes are read, then we know that it read the whole file. If os.EOF is detected before all bytes are read, discard and start again.
In normal C, one would shutdown(fd, SHUT_WR) the TCP connection to indicate EOF to the other side. You can do this in go as well:
func shutdownWrite(conn net.Conn) {
// anonymous interface. Could explicitly use TCP instead.
if v, ok := conn.(interface{ CloseWrite() error }); ok {
v.CloseWrite()
}
}
See https://golang.org/src/net/tcpsock_posix.go?s=2073:2109#L75
Everything works, if you close the connection from the sender's side.
I made the same thing now - file transfer through TCP. Everything works fine if you add
defer conn.Close()
after opening the connection.
For example:
conn, err := net.Dial("tcp", client)
defer conn.Close()