Reputation: 2201
When doing async socket IO with epoll on non-blocking sockets, reading seems straightforward: Just epoll_wait
until the socket is ready for reading, and read until you get EAGAIN
/EWOULDBLOCK
.
But how do you send? Presumably doing a single large send
operation would block, so you will always get EAGAIN
/EWOULDBLOCK
. What are you meant to do?
Upvotes: 1
Views: 2041
Reputation: 69286
Presumably the kernel will not be able to send all data right away, that's why send
on success returns the number of bytes sent. The important thing is that the number returned can (and most likely will) be lower than the total length specified in the call. You will only get EAGAIN/EWOULDBLOCK
as an answer if no bytes at all can be sent. So when sending a large amount of data, you just need to correctly handle the (very likely) possibility that not all data is sent at once.
Note: this is different for datagram (UDP) sockets, since partial datagrams cannot be sent. See POSIX: Return value from write() on UDP socket for more information.
Here's an example assuming a SOCK_STREAM
(TCP) socket:
size_t len;
size_t sent;
char *buf;
/* ... prepare data ... */
while (sent < len) {
ssize_t n;
if ((n = send(sockfd, buf + sent, len - sent, flags)) == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
continue;
perror("send failed");
exit(1);
}
sent += n;
}
Upvotes: 5
Reputation: 595827
send/to()
will send as many bytes as it can, returning how many bytes it was actually able to give the kernel to send.
If you are using a TCP socket, call send()
in a loop until EITHER all of your bytes have been sent OR EAGAIN
/EWOULDBLOCK
is reported. In the latter case, stop the loop and cache the remaining bytes somewhere.
If you are using a UDP socket, send/to()
can only send whole datagrams, so don't use a loop at all, and if EAGAIN
/EWOULDBLOCK
is reported then cache the entire datagram.
Whenever epoll
indicates a socket is writable, send any cached bytes/datagrams for that socket as needed, removing only successful bytes/datgrams from the cache, until EITHER the cache is cleared OR EAGAIN
/EWOULDBLOCK
is reported. Leave unsent bytes/datagrams in the cache.
Whenever you need to send new TCP bytes, or a new UDP datagram, if the socket's cache is not empty then append the bytes/datagram to the end of the cache and move on, otherwise attempt to send the bytes/datagram immediately, caching if EAGAIN
/EWOULDBLOCK
is reported, as described above.
Upvotes: 3