azizulhakim
azizulhakim

Reputation: 658

GoLang File Transfer Stops Without Any Error

I've running a simple file transfer code in go. From the server side I try to read 1024 bytes of data at a time. From client side I'm using the io.Copy function to transfer the file. The file transfer completes successfully 70% of the time. But in 30% of time it fails. It gets stuck on connection.Read function. Through some experiments I saw that it happens only on the occasion where previous Read operation reads less than 1024 bytes of data.

So from my code, ideally it should read 1024 bytes of data on all successive Read except the very last Read where the file transfer is complete. But on some occasion if it reads less than 1024 bytes, the next Read operation gets stuck without throwing any error. Here is my code:

  1. Server.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")
    

For my case, number of sent bytes is correct, number of received bytes is also correct on successful transfer. The problem happens for the same file.

Upvotes: 3

Views: 1154

Answers (1)

weberc2
weberc2

Reputation: 7908

TL;DR: This should be all you need to copy a file.

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

If you need to copy in chunks while doing some logic in between copies (for example, printing the bytes read), you can use 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
    }
}

Upvotes: 5

Related Questions