3

My data is naturally segmented, and comes from different sources so I use the writev function as follows.

char *buf0 = "short string\n";
struct bar *my_bar;
my_baz = get_my_baz();
iov[0].iov_base = buf0;
iov[0].iov_len = strlen(buf0);
iov[1].iov_base = my_bar;
iov[1].iov_len = sizeof (struct bar);
bytes_written = writev (sockfd, iov, 3);

I want to send all my data. What if writev only write partial data in one time, for example:

bytes_written = 1;

How do I to continue to send the remain data? In write function, we can use this method, how about writev?

ZachB
  • 13,051
  • 4
  • 61
  • 89
zwfars
  • 31
  • 2
  • Important note in the documentation: "The data transfers performed by `readv()` and `writev()` are atomic: **the data written by `writev()` is written as a single block** that is not intermingled with output from writes in other processes" (Note: this guarantee is not part of POSIX, and OSes other than Linux might write only part of the data) – Ben Voigt Jul 21 '17 at 02:07
  • 1
    @BenVoight That doesn't preclude a short write in non-blocking mode. – user207421 Jul 21 '17 at 02:09
  • 1
    @EJP: Of course it does, a short write or even automatically resumed operation wouldn't preserve atomicity. – Ben Voigt Jul 21 '17 at 02:10
  • @BenVoigt Your quotation talks about 'the data transfers performed'. I.e. what *actually* gets written. It doesn't state that all the data *presented by the user* gets written regardless of non-blocking mode, no space in the socket send buffer, etc. That would be a violation of non-blocking-mode semantics. – user207421 Jul 21 '17 at 02:30
  • @EJP: Start with the basic definition of *atomic*. It's perfectly possible to have non-blocking semantics for an atomic transfer, either the entire block fits in the buffer, or the call fails without writing anything, returning -1 and setting errno to EWOULDBLOCK. – Ben Voigt Jul 21 '17 at 04:02
  • @BenVoigt I can only repeat. It doesn't say that all the data presented is written. It says that the data that *is* written is written atomically. – user207421 Mar 22 '20 at 01:59
  • @user207421: Atomic means exactly that the data is treated as one indivisible chunk, either all written or none of it is. A partial write is not "atomic". Atomic means that the operation cannot be split up into parts, so it's not possible for one part to succeed and one to fail, because **there are no parts**. – Ben Voigt Mar 23 '20 at 06:05
  • 1
    It is empirically possible for `writev` to do a short write. I made a test program that opened a non-blocking TCP stream to a remote server and wrote N iovecs. Each iovec was 1024B of the sequence "1234567890" repeated. `writev` did short writes of different lengths depending on the remote server - for `www.google.com:80` it was at 106350B, for `www.microsoft.com:80` at 1048576B, for `www.cloudflare.com:80` at 72800B. With microsoft and cloudflare a second writev failed because the remote server had hung up; with google it succeeded with an additional 107768B written. Kernel 5.10.16, x86_64 – Arnavion Mar 12 '21 at 08:32
  • Does this answer your question? [Techniques for handling short reads/writes with scatter-gather?](https://stackoverflow.com/questions/5853675/techniques-for-handling-short-reads-writes-with-scatter-gather) – ZachB Aug 12 '23 at 04:35

1 Answers1

6
  1. Increment iov[0].iov_base by bytes_written.
  2. Decrement iov[0].iov_len by bytes_written.
  3. Take care of underflows, i.e. if iov[0].iov_len goes negative, remember it, set it to zero, and propagate the difference into iov[1] in the same way as (1) and (2), and so on until closure.

However if you're in blocking mode this is a non-issue, as the case of a short write can never arise.

user207421
  • 305,947
  • 44
  • 307
  • 483