0xpentix
0xpentix

Reputation: 742

Get progress of socket read operation

I'd like to write little file transfer program in C (I'm working on Linux). I'm quite new to sockets programming, but I already managed to write little server and client programs.

My question:

If I have something like this:

int read_bytes = read(socket_id, buffer, 4096);

While reading from the socket, how can I get the progress of reading? For example I want to display every 100ms how many bytes have been transferred so far. I'm pretty sure I have to use threads or other async functions here. Is there a function so I can get the number of bytes read and the number of bytes to read?

Update 1: Accumulating read()

int total_read_bytes=0, read_bytes;
char buffer[4096];
do {
    read_bytes = read(socket_id, buffer, 4096);
    total_read_bytes += read_bytes;
} while(read_bytes > 0); /* Read to end or read failed */ 

Isn't this very, very inefficient? (For example to transfer a 1MiB file)

Thank you

Upvotes: 2

Views: 439

Answers (2)

Tony Delroy
Tony Delroy

Reputation: 106196

Each recv call will block until it's read some more, but it won't (by default / sans MSG_WAITALL) wait for the supplied buffer to be full. That means there's no need to reduce the buffer size in an effort to get more frequent updates to the total bytes read information, you can trivially keep a total of recv() return values that updates as packets arrive (or as fast as your app can process them from the OS buffers).

As you observe, if that total is being updated 100 times a second, you probably don't want to issue 100 screen updates, preferring to limit them to your 100ms min interval. You could use a timer/alarm to manage that, but then you have more edge cases to see if the timer is already pending etc.. It's probably simpler just to use two threads where one checks periodically if an update is needed:

  • thread1:
    • while ((n_bytes = recv(...)) > 0)
      • total_bytes += n_bytes;
    • set screen-updater-termination flag
  • thread2:
    • last_total_bytes = -1;
    • while the screen-updater-termination flag's not set
      • sleep 100ms
      • if last_total_bytes != total_bytes
        • update screen
        • last_total_bytes = total_bytes

Of course you'll need to use a mutex or atomic operations to coordinate some of these actions.

Is there a function so I can get... the number of bytes to read?

Not from TCP itself - it doesn't have a notion of message sizes, and the API just ensures an app receives the bytes in the same order they were sent. If you want to be able to display a "N bytes received so far, X more expected", then at the application protocol level, the sending side should prefix the data in a logic message with the size - commonly in either a fixed width binary format (ideally using htonl or similar to send and ntohl on the recv side to avoid endian issues), or in a textual representation that's either fixed with or separated from the data by a known sentinel character (e.g. perhaps a NUL, a space or newline).

Upvotes: 1

GuLearn
GuLearn

Reputation: 1864

If you have control to the code of both the server and the client, you can let the sender to tell the receiver the size of the file before actually sending the file. For example, using the first 8 bytes in the message. That's the number of bytes to read.

By accumulating the read_bytes in your example, you can get number of bytes read

Upvotes: 1

Related Questions