clinuxsocketsepoll

How to write to a nonblocking socket (when using epoll)


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?


Solution

  • 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;
    }