Search code examples
c++socketsblockingfile-descriptor

What does write(2) return of zero mean and will I eventually make progress (non-zero result)?


I have a socket over TCP that I am writing to in a C++03 program. In some cases, I get a zero return result from write(). The write(2) man page states in part:

On success, the number of bytes written is returned (zero indicates nothing was written). On error, -1 is returned, and errno is set appropriately.

So, does a zero really mean no error and I should just call write again until everything I have has been written? In other words, should I just treat a zero just like I already do for a partial write where the number of bytes written is less than the count I passed to write and just keep trying until I reach a total of count bytes written?

I want to make sure I will not get into an infinite loop with write returning zero continuously and never making progress. Should I be calling select() first to make sure the file descriptor is ready before calling write? I've got blocking enabled on the file descriptor.


Solution

  • Although in theory, it will probably either get through or get an error eventually, I would build some safety against infinite loops, just in case.

    Calling select to wait for the hardware may work (and it's certainly better than just looping back trying immediately again, which will almost certainly waste some CPU time - how much depends on a lot of things), but it's a TOCTOU problem - some other program in your system may have got there before you and (again) filled the systems memory available to transmit through by the time you get to write.

    So, I would do something along these lines:

    int write_zero_count = 0; 
    
    while(not_all_written)
    {
      int res;
      res = select(...);
      ... check if we can write, etc ... 
      res = write(...);
      if (res == 0)
      {
         write_zero_count++;
         if (write_zero_count > max_zero_writes)
         {
            error("Got many writes that sent zero bytes, not good");
            .... do other stuff to log and recover from error or exit? ...
         } 
      }
      else
      {
          write_zero_count = 0;
      }
    }