I am trying to determine by reading the POSIX specification if a
conforming send() implementation on a non blocking socket is allowed
to return on partial writes. From what I understand if the socket is
non blocking and if there isn't enough space in the buffer for the
data to send then send will fail with EAGAIN. If however there is
enough space it will succeed with all bytes written is it not?
Example,
int res = send(sock, "1", 2, MSG_DONTWAIT);
(MSG_DONTWAIT is not standard but just imagine that instead of it the
socket "sock" is non blocking)
Can I assume for a conforming POSIX implementation that "res" will be
either -1 (and errno set to whatever error happened) or be 2 (fully
successful send)? If not can you describe a case where it may not be
so?
Thanks!
--
Dizzy
AFAIK, send(2)/write(2) can always do a partial write, even in non-
blocking mode. In your example, if only one byte is available in the
buffer, send() should put one byte into the buffer and return 1. So
you need to prepare for this eventuality.
The wording in the FreeBSD man page makes it more clear: "If no
messages space is available at the socket to hold the message to be
transmitted, then send() normally blocks, unless the socket has been
placed in non-blocking I/O mode". So blocking or EAGAIN happens only
when the buffer is completely full.
This makes sense if you think about it. Suppose that, unbeknownst to
you, your socket has a buffer that is only one byte long. Under the
semantics you propose, trying to send() 2 bytes would result in an
EAGAIN. You would ordinarily wait and try again later, but the call
would never succeed. However, if send() writes one of the bytes, then
progress is made and eventually everything will be written.
(Replacing 1 and 2 with more realistic numbers will give a more
realistic example.)
> AFAIK, send(2)/write(2) can always do a partial write, even in non-
> blocking mode. In your example, if only one byte is available in the
> buffer, send() should put one byte into the buffer and return 1. So
> you need to prepare for this eventuality.
I'm fairly sure that your "always" is incorrect.
While for a stream socket partial writes make sense, what about pipes
and datagram sockets? In the case of pipes, writes below a certain size
must be atomic, and for datagrams it makes no sense to do a partial write.
Chris
Ehh ... all writes targetting datagram sockets must be atomic (or
return an error). There is no way to 'preserve message boundaries'
otherwise.
Regarding the original question: I feel strongly inclined to assume
that this refers to the 'possibility' to use TCP for
message boundary preserving transmissions. And this isn't possible.
> I am trying to determine by reading the POSIX specification if a
> conforming send() implementation on a non blocking socket is allowed
> to return on partial writes. From what I understand if the socket is
> non blocking and if there isn't enough space in the buffer for the
> data to send then send will fail with EAGAIN. If however there is
> enough space it will succeed with all bytes written is it not?
It totally depends on the protocol. The rules for files are nothing
like the rules for pipes which are nothing like the rules for datagram
sockets which are different from the rules for stream sockets.
DS
That seems to be not what POSIX says:
"If space is not available at the sending socket to hold the message to be transmitted, and the socket file descriptor does not have
O_NONBLOCK set, send() shall block until space is available. If space
is not available at the sending socket to hold the message to be
transmitted, and the socket file descriptor does have O_NONBLOCK set,
send() shall fail."
My reading of "to hold the message" means it needs to have space for
the full data to be sent otherwise it returns with EAGAIN.
> This makes sense if you think about it. Suppose that, unbeknownst
> to
> you, your socket has a buffer that is only one byte long. Under the
> semantics you propose, trying to send() 2 bytes would result in an
> EAGAIN.
Well then the POSIX wording is wrong? I would have wanted a EMSGSIZE
in that case but that's probably sent only for datagram sockets.
--
Dizzy
> That seems to be not what POSIX says:
> "If space is not available at the sending socket to hold the message to be transmitted, and the socket file > descriptor does not have
> O_NONBLOCK set, send() shall block until space is available. If space
> is not available at the sending socket to hold the message to be
> transmitted, and the socket file descriptor does have O_NONBLOCK set,
> send() shall fail."
> My reading of "to hold the message" means it needs to have space for
> the full data to be sent otherwise it returns with EAGAIN.
No, that is not correct. The "full data to be sent" only constitutes a
message for protocols that honor message boundaries. For protocols
like TCP, the "full data to be sent" is not a message because there
are no message boundaries.
> Well then the POSIX wording is wrong? I would have wanted a EMSGSIZE
> in that case but that's probably sent only for datagram sockets.
Stream sockets (like TCP) do not send messages.
DS
> On Sep 8, 5:08 am, dizzy <di...@roedu.net> wrote:
>> My reading of "to hold the message" means it needs to have space
>> for the full data to be sent otherwise it returns with EAGAIN.
>
> No, that is not correct. The "full data to be sent" only constitutes
> a message for protocols that honor message boundaries. For protocols
> like TCP, the "full data to be sent" is not a message because there
> are no message boundaries.
OK, so POSIX is fine to say about send() that it always fails with
EAGAIN on non blocking sockets when there is no space for the message
to be sent and what I missed is the definition of "message". In case
of message based protocols it's defined by the protocol details and in
the case of PF_INET/SOCK_STREAM/IPPROTO_TCP a message is a byte then?
What about the (not sure if standard) SO_SNDLOWAT socket option. By
default I know it's "1" and increasing it means that even for TCP/IP
EAGAIN will be returned if available buffer size is lower than the
SO_SNDLOWAT value?
>> Well then the POSIX wording is wrong? I would have wanted a
>> EMSGSIZE in that case but that's probably sent only for datagram
>> sockets.
>
> Stream sockets (like TCP) do not send messages.
But the POSIX reference doesn't say anything about non blocking
semantics of send() other than that sentence which mentions "message".
So it means TCP does have a message only that is always 1 byte size
(or something like that).
--
Dizzy
> OK, so POSIX is fine to say about send() that it always fails with
> EAGAIN on non blocking sockets when there is no space for the message
> to be sent and what I missed is the definition of "message". In case
> of message based protocols it's defined by the protocol details and in
> the case of PF_INET/SOCK_STREAM/IPPROTO_TCP a message is a byte then?
There are no messages for TCP. TCP is not a message-based protocol.
> What about the (not sure if standard) SO_SNDLOWAT socket option. By
> default I know it's "1" and increasing it means that even for TCP/IP
> EAGAIN will be returned if available buffer size is lower than the
> SO_SNDLOWAT value?
Maybe. I would strongly advise not messing with SO_SNDLOWAT.
> > Stream sockets (like TCP) do not send messages.
> But the POSIX reference doesn't say anything about non blocking
> semantics of send() other than that sentence which mentions "message".
> So it means TCP does have a message only that is always 1 byte size
> (or something like that).
TCP does not have messages. TCP is a byte-stream protocol. All it has
is bytes. The POSIX documentation is not extremely well organized on
this. You have to find the sections that tell you which sections
apply.
DS