3

After select returns with write fd set for a tcp socket. If I try to send data on that socket, what is the minimum guaranteed size of data to be sent at once using send api? I understand that I have to run a loop to make sure all the data is sent. Still i want to understand what is the minimum guaranteed data sent and why?

CCoder
  • 2,305
  • 19
  • 41
  • 1
    Why do you expect there to be a minimum guaranteed size? – Anish Ramaswamy Apr 23 '13 at 09:06
  • @AnishRam Because there is MSS of 536 for TCP(for IPv4 compatible nodes). And i expected that if i call send with data size < 536 it should not result in partial send. – CCoder Apr 23 '13 at 09:10
  • Hmm, so is a partial send equivalent to saying the data is split into segments? – Anish Ramaswamy Apr 23 '13 at 09:20
  • You can't expect that. Some or all of the data might get piggybacked onto a prior segment by the Nagle algorithm, for example. You can't make any assumptions about segmentising and packetising in TCP. – user207421 Apr 23 '13 at 23:12

4 Answers4

1

This has come up before. I'm still searching for the referenced answer.

Let's start with the function prototype for send()

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

For blocking TCP sockets - all the documentation will suggest that send() and write() will return a value between [1..len], unless there was an error. However, the reality is that no one I know has ever observed send() returning something other than -1 (error) or just "len" in the success case to indicate all of "buf" was sent in one call. I've never felt good about this, so I code defensively and just put my blocking send calls in a loop until the entire buffer is sent.

For non-blocking TCP sockets - you should just code as if the minimum was "1" (or -1 on error). Don't make any assumptions about a minimum data size.

And for recv(), you should always assume recv() will return some random value between 1..len in the success case, or 0 (closed), or -1 (error). Don't EVER assume recv will return a full buffer.

selbie
  • 100,020
  • 15
  • 103
  • 173
  • I'll augment my answer with some other discusson: http://stackoverflow.com/questions/2618736/why-is-it-assumed-that-send-may-return-with-less-than-requested-data-transmitted – selbie Apr 23 '13 at 09:31
  • I completely agree and I also understand that i should call send in a loop. I am curious to know the guaranteed size and also the reason for the limitation. My understanding was MTU size of the nodes limit the size of the data sent in one send call. – CCoder Apr 23 '13 at 09:31
  • No, MTU just influence how much the kernel will send over an adapter. But this usually doesn't influence the send call itself. A blocking send() for a large buffer will likely translate to many packets and TCP frames being generated. – selbie Apr 23 '13 at 09:34
  • Here's the original question I was searching for: http://stackoverflow.com/questions/14700906/socket-programming-send-return-value – selbie Apr 23 '13 at 09:36
  • in modern world of network hardware/software, then even to reach near by PC your packet passing things like wifi routers/firewalls MTU of your 'source' machine doesn't have that much meaning at all, until you are building very specific network configuration. That can be considered as a 'wish' rather then 'instruction' – evilruff Apr 23 '13 at 09:38
0

From the official POSIX reference:

A descriptor shall be considered ready for writing when a call to an output function with O_NONBLOCK clear would not block, whether or not the function would transfer data successfully.

As you see it doesn't actually mentions any size, or that the write will even be successful, just that you will be able to write to the socket without blocking.

So the answer is that there is no minimum guaranteed size.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

I dont think that on a POSIX layer you have any control over that. send() will accept anything you pass into internal buffers of TCP/IP stack implementation. And what happens next with it it's already another story which you can watch over using same select() call.

If you are asking about size which will fit in one packet that's MTU (but this assumption also should be used with care in regards of fragmentation and reassembling of the packets on the way)

UPD:

I will answer your comment here. No, you shouldn't bother about fragmentation at all. Leave it to TCP/IP stack. There are a lot of reasons why you shouldn't do this.. One as an example. Your application works on Application(7) layer of OSI model (although I consider OSI model in most cases to be an evil thing, it's really applicable for this example). And from this layer you trying to affect functionality/properties of a logic which is on much lower layers (Session/Transport). You shouldn't do this. POSIX calls like send(), recv() are designed to give your application an ability to instruct underneath layers that you need to pass certain amount of data and you have a way to monitor an execution of a command ( select()), that's all you have to do. And lower layers suppose to do their best to deliver data you instruct them to do in most optimal way depending on OS network settings/etc.

UPD2: everything above mostly consider NON_BLOCKING sockets. Sorry forgot to mention this, I don't use blocking sockets in my projects for ages.. in case your socket is blocking I still would consider to pass everything at once and just wait for operation result in another thread for example, because trying to optimise this could lead to very OS/drivers dependant code.

evilruff
  • 3,947
  • 1
  • 15
  • 27
  • I was coming from exact that point. My understanding is that if MTU size of all nodes in the path is > 576 then you don't need to fragment in case of IPv4. So should i not be able to send data < MSS in a single send call ? – CCoder Apr 23 '13 at 09:12
  • I've updated an answer – evilruff Apr 23 '13 at 09:22
0

When select() indicates that a socket is writable it is guaranteed you can transfer at least one byte without incurring EWOULDBLOCK or EAGAIN. Nothing to say you won't incur a different error though :-)

user207421
  • 305,947
  • 44
  • 307
  • 483