英文:
when all I get is EOF from a net.TCPConn, how do I know if the connection has been dropped?
问题
根据godocs的说明:
“当没有更多输入可用时,Read函数返回的错误是EOF。函数应该只返回EOF来表示输入的优雅结束。如果在结构化数据流中意外发生EOF,则适当的错误是ErrUnexpectedEOF或其他提供更多详细信息的错误。”
在我的程序中,我希望得到ErrUnexpectedEOF,但实际上并没有得到。即使在客户端在发送文件的过程中意外终止,我始终只得到EOF。
所以,我陷入了困境。成功传输完全的文件会在末尾发送EOF。而在传输过程中出现错误并中途退出的文件也会将EOF作为错误发送。我不知道传输之前文件的总大小。
是否有任何其他信息可以从net.TCPConn中获取,以了解这是一个完整的文件还是不完整的文件?
英文:
The godocs say:
"EOF is the error returned by Read when no more input is available. Functions should return EOF only to signal a graceful end of input. If the EOF occurs unexpectedly in a structured data stream, the appropriate error is either ErrUnexpectedEOF or some other error giving more detail."
and in my program I would love
love to get ErrUnexpectedEOF, but I don't. I always get just EOF even when the client terminates in the middle of sending a file.
so, i'm stuck. Successful files that transfer 100% of the way thru send EOF at end. And files that quit 50% thru with error also send EOF as the error. I do not know the total size of the file before the transfer.
Is there any more information I could get from the net.TCPConn to know was this a full file or not?
答案1
得分: 1
TCP是一种流式协议,传输的是字节流。这就是为什么文件传输协议(如FTP)是基于TCP发明/实现的原因。
但是(不建议/作为思想实验),如果你可以将文件分成不包含特定字符/字节(比如base64 + \n作为特定字符)的块,那么你可以将该特定字符作为分隔符。
现在,如果我们使用类似于以下代码的函数来处理连接:
func (srv *Server) handler(conn net.Conn) {
//...
defer srv.closeConnection(conn, nil)
reader := bufio.NewReader(conn)
writer := bufio.NewWriter(conn)
//...
conn.SetDeadline(time.Now().Add(conf.ClientTimeout))
for {
select {
case <-conf.QuitSignal:
return
default:
line, err := reader.ReadBytes('\n')
if err != nil {
return
}
//...
}
conn.SetDeadline(time.Now().Add(conf.ClientTimeout))
}
}
func (srv *Server) closeConnection(conn net.Conn, err error) {
conn.Close()
//...
}
从Reader.ReadBytes
的文档中,我们可以看到只有当返回的数据不以分隔符结尾时,ReadBytes
才会返回err != nil
。这样我们就可以识别出一个损坏的块。
英文:
TCP is a streaming protocol; a stream of bytes. That's why file transfer protocols invented/implemented upon TCP, like FTP (File Transfer Protocol).
But (not recommended/thought experiment) if you can send your files in chunks that does not contain a certain character/byte (like base64 + \n as that certain character), then you can use that certain character as delimiter.
Now if we handle our connections using a function similar to this:
func (srv *Server) handler(conn net.Conn) {
//...
defer srv.closeConnection(conn, nil)
reader := bufio.NewReader(conn)
writer := bufio.NewWriter(conn)
//...
conn.SetDeadline(time.Now().Add(conf.ClientTimeout))
for {
select {
case <-conf.QuitSignal:
return
default:
line, err := reader.ReadBytes('\n')
if err != nil {
return
}
//...
}
conn.SetDeadline(time.Now().Add(conf.ClientTimeout))
}
}
func (srv *Server) closeConnection(conn net.Conn, err error) {
conn.Close()
//...
}
From the documentation of Reader.ReadBytes
we read ReadBytes returns err != nil if and only if the returned data does not end in delimiter. This way we can recognize a broken chunk.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论