当我从net.TCPConn中只收到EOF时,我如何知道连接是否已经断开?

huangapple go评论91阅读模式
英文:

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 &lt;-conf.QuitSignal:
			return
		default:
			line, err := reader.ReadBytes(&#39;\n&#39;)
			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.

huangapple
  • 本文由 发表于 2016年9月27日 03:29:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/39710874.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定