【问题标题】:GoLang File Transfer Stops Without Any ErrorGoLang 文件传输停止且没有任何错误
【发布时间】:2016-11-05 03:14:45
【问题描述】:

我在go 中运行了一个简单的文件传输代码。从服务器端,我尝试一次读取 1024 字节的数据。从客户端我使用io.Copy 函数来传输文件。文件传输在 70% 的时间内成功完成。但是在 30% 的时间里它会失败。它卡在connection.Read 函数上。通过一些实验,我发现只有在之前的Read 操作读取的数据少于1024 字节的数据时才会发生这种情况。

所以从我的代码中,理想情况下,它应该读取所​​有连续的Read 上的1024 字节数据,除了文件传输完成的最后一个Read。但在某些情况下,如果它读取的字节数少于 1024 字节,则下一个 Read 操作会卡住而不会引发任何错误。这是我的代码:

  1. 服务器.go

    fileBuffer := make([]byte, BUFFER_SIZE)     //BUFFER_SIZE is a constant of 1024
    bytesRead := int64(0)
    count := 0
    for {
        if fileSize-bytesRead < int64(BUFFER_SIZE) {        //fileSize is the size of file in bytes, which I calculated earlier.
            fileBuffer = make([]byte, fileSize-bytesRead)
        }
    
        fmt.Println("Reading ", BUFFER_SIZE, " bytes of data")
    
        n, err := connection.Read(fileBuffer)
    
        count++
    
        fmt.Println("Completed reading", n, " bytes of data, count=", count)
    
        file.Write(fileBuffer[0:n])
    
        bytesRead += int64(n)
        fmt.Println("So far read", bytesRead, " bytes of data")
    
        if err != nil {
            fmt.Println(err)
        }
    
        if err == io.EOF {
            result.Message = "File transfer incomplete"
            break
        }
    
        if bytesRead >= fileSize {
            result.Message = "File transfer complete"
            break
        }
    }
    
  2. Client.go

    n, err := io.Copy(conn, file)
    fmt.Println(n, " bytes sent")
    

就我而言,发送的字节数是正确的,成功传输时接收的字节数也是正确的。问题发生在同一个文件上。

【问题讨论】:

  • 您没有在非 EOF 错误上中断,这可能会卡住,并且您没有检查写入计数或错误。为什么不直接使用 io.Copy 或 io.CopyBuffer?
  • 是的,我没有打破非 EOF 错误。但如果有任何错误,我会打印。所以在错误的情况下,我希望在控制台上看到一些东西。它只是一个测试应用程序,我不需要它是完美的。我只需要了解为什么文件传输有时会卡住。此外,我正在使用 io.Copy 并打印从客户端发送的字节数,这始终是正确的。
  • 您绝对应该在写入文件之前检查错误。如果出现错误(n 不一定定义),永远不要写入文件。

标签: go


【解决方案1】:

TL;DR:这应该是复制文件所需的全部内容。

if _, err := io.Copy(file, connection); err != nil {
    // handle error
}

如果您需要在副本之间执行一些逻辑(例如,打印读取的字节)时需要分块复制,您可以使用io.CopyN

totalRead := int64(0)
for {
    n, err := io.CopyN(outfile, infile, 1024)
    totalRead += n
    // print bytes read followed by a carriage return
    fmt.Printf("Bytes read: %d\r", totalRead)
    if err != nil {
        if err == io.EOF {
            fmt.Println() // print a newline
            break
        }
        // handle error
    }
}

【讨论】:

  • 我很感激。这是一个更好、更清晰的代码,我将用它替换我的代码。但我也想知道我的代码出了什么问题。这里似乎没有任何问题。
  • 是的,这可能是一个原因,但事实并非如此。因为每次阅读后我都会打印一份。所以如果它是无限循环,我会在控制台上看到无限打印。为了仔细检查,我删除了新的缓冲区分配并添加了一些额外的打印内容,确认我的代码中不是这种情况。
  • 事实上我对你的代码也有同样的问题。它在某个时候卡住了。不知道出了什么问题。
  • 您的连接听起来有问题(发件人、网络或您的 connection.Read() 方法有问题)。
猜你喜欢
  • 1970-01-01
  • 2015-07-15
  • 1970-01-01
  • 1970-01-01
  • 2017-03-08
  • 1970-01-01
  • 1970-01-01
  • 2016-06-22
  • 2020-01-23
相关资源
最近更新 更多