clinuxsocketstcp

Packing multiple writes into single TCP packet


I have a sequence of send() calls to write bytes to a TCP socket. Is it possible to force the socket to only send TCP packets when they are either full (exceeding the MTU) or I explicitly indicate that I'm done sequentially calling send()?

Specifically, I have some code like:

// these are user-provided, I don't control these:

void* buf1;
size_t len1;
void* buf2;
size_t len2;
void* buf3;
size_t len3;

// I control this call sequence:

if (send(sck, buf1, len1, 0) < 0 ||
    send(sck, buf2, len2, 0) < 0 ||
    send(sck, buf3, len3, 0) < 0) {
  ...
}

And I'd like to somehow minimize the number of underlying packets that are sent.

This could be done by creating an intermediate buffer then after all the send calls, I could then manually send that buffer but I'd like to avoid creating an intermediate buffer because some of the data may be quite large and it would require an extra copy of that data. In other words, I am looking to zero-copy send the data. Is this possible?

Note: I am aware that TCP is not a packet-based protocol. I've searched around and there are a number of answers that give that pedantic response that packets don't really exist and while it's perhaps semantically true, it's not particularly helpful because there are still IP packets underneath.


Solution

  • You can do writev() to write them all in one shot. But in any case, you cannot control how or when the socket interface will pack the data and send it. It depends on network congestion, internal buffer size, MTU and several other causes.

    TCP uses a MTU which is normally adjusted along the connection life, based on the MTUs of all the interfaces in the path between the connection sides. This is dynamically calculated, based on the ICMP fragmentation needed packets received. So, allowing the user to interfere on that fine tuned algorithm is a dangerous bend. IMHO, the sooner the socket has the data ready to send, the sooner the receiver gets it.