3

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.

Endophage
  • 21,038
  • 13
  • 59
  • 90
azizulhakim
  • 658
  • 7
  • 24
  • 2
    You're not breaking on a non-EOF error, which can get stuck, and you're not checking the Write count or error. Why not just use io.Copy or io.CopyBuffer? – JimB Nov 04 '16 at 18:10
  • Yes, I'm not breaking on non-EOF error. But I'm printing if there is any error. So in error case, I'm expecting to see something on the console. It is just a test application and I don't need it be perfect. I just need to understand why the file transfer gets stuck on some occasion. Also I'm using the io.Copy and printing the number of bytes sent from the client side, which is correct always. – azizulhakim Nov 04 '16 at 18:13
  • You should definitely check the error before writing to the file. And in case of an error (where `n` is not necessarily defined) never write to a file. – Matthias247 Nov 04 '16 at 18:19

1 Answers1

5

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
    }
}
weberc2
  • 7,423
  • 4
  • 41
  • 57
  • I appreciate it. that is a better and cleaner code and I'll replace my code with that. But I also want to know what is going wrong with my code. Nothing seems to be incorrect here. – azizulhakim Nov 04 '16 at 18:32
  • yes, that could be a reason except that it is not. Because I've a print after each read. So if it were infinite loop, I would see infinite print on the console. To double check, I removed the new buffer allocation and put some extra print which confirmed it is not the case in my code. – azizulhakim Nov 04 '16 at 18:53
  • In fact I'm having the same issue with your piece of code. It gets stuck at some point. Not sure whats going wrong. – azizulhakim Nov 04 '16 at 19:17
  • It sounds like there is something wrong with your connection (either a problem with the sender, the network, or your connection.Read() method). – weberc2 Nov 04 '16 at 19:20