Blocking socket returns EAGAIN
Solution 1
It's possible that you have a nonzero receive timeout set on the socket (via setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,...)
) as that would also cause recv to return EAGAIN
Solution 2
Is it possible that you're using MSG_DONTWAIT
is being specified as part of your flags? The man
page says EAGAIN
will occur if no data is available and this flag is specified.
If you really want to force a block until the recv()
is somewhat successful, you may wish to use the MSG_WAITALL
flag.
Jason
For links to some of my open source projects: https://github.com/eteran
Updated on July 12, 2022Comments
-
Jason almost 2 years
One of my projects on Linux uses blocking sockets. Things happen very serially so non-blocking would just make things more complicated. Anyway, I am finding that often a
recv()
call is returning-1
witherrno
set toEAGAIN
.The
man
page only really mentions this happening for non-blocking sockets, which makes sense. With non-blocking, the socket may or may not be available so you might need to try again.What would cause it to happen for a blocking socket? Can I do anything to avoid it?
At the moment, my code to deal with it looks something like this (I have it throw an exception on error, but beyond that it is a very simple wrapper around
recv()
):int ret; do { ret = ::recv(socket, buf, len, flags | MSG_NOSIGNAL); } while(ret == -1 && errno == EAGAIN); if(ret == -1) { throw socket_error(strerror(errno)); } return ret;
Is this even correct? The
EAGAIN
condition gets hit pretty often.EDIT: some things which I've noticed which may be relevant.
I do set a read timeout on the socket using
setsockopts()
, but it is set to 30 seconds. theEAGAIN
's happen way more often than once every 30 secs. CORRECTION my debugging was flawed,EAGAIN
's don't happen as often as I thought they did. Perhaps it is the timeout triggering.For connecting, I want to be able to have connect timeout, so I temporarily set the socket to non-blocking. That code looks like this:
int error = 0; fd_set rset; fd_set wset; int n; const SOCKET sock = m_Socket; // set the socket as nonblocking IO const int flags = fcntl (sock, F_GETFL, 0); fcntl(sock, F_SETFL, flags | O_NONBLOCK); errno = 0; // we connect, but it will return soon n = ::connect(sock, addr, size_addr); if(n < 0) { if (errno != EINPROGRESS) { return -1; } } else if (n == 0) { goto done; } FD_ZERO(&rset); FD_ZERO(&wset); FD_SET(sock, &rset); FD_SET(sock, &wset); struct timeval tval; tval.tv_sec = timeout; tval.tv_usec = 0; // We "select()" until connect() returns its result or timeout n = select(sock + 1, &rset, &wset, 0, timeout ? &tval : 0); if(n == 0) { errno = ETIMEDOUT; return -1; } if (FD_ISSET(sock, &rset) || FD_ISSET(sock, &wset)) { socklen_t len = sizeof(error); if (getsockopt(SOL_SOCKET, SO_ERROR, &error, &len) < 0) { return -1; } } else { return -1; } done: // We change the socket options back to blocking IO if (fcntl(sock, F_SETFL, flags) == -1) { return -1; } return 0;
The idea is that I set it to non-blocking, attempt a connect and select on the socket so I can enforce a timeout. Both the set and restore
fcntl()
calls return successfully, so the socket should end up in blocking mode again when this function completes. -
Jason about 15 yearsI just grepped my source tree, MSG_DONTWAIT is not used.
-
Jason about 15 yearsyes, but it is set to 30000 milliseconds, I get the EAGAIN's way more often than that. Pretty much constatnly.
-
Jason about 15 yearsCORRECTION my debugging was flawed, EAGAIN's don't happen as often as I thought they did. Perhaps it is the timeout triggering.
-
yixiang over 4 yearsFor anyone who want a reference, check here and search "SO_RCVTIMEO".