Blocking socket returns EAGAIN

One of my Linux projects uses blocking sockets. Everything happens very consistently, so non-blocking will simply complicate the situation. Anyway, I find that often calling recv() returns -1 with errno set to EAGAIN .

The man page really mentions this for non-blocking sockets, which makes sense. With non-blocking, the socket may or may not be available, so you may need to try again.

What could happen to a blocking socket? Can I do anything to avoid this?

At the moment, my code for working with it looks something like this (for me it throws an exception on error, but in addition 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 right? The EAGAIN is pretty common.

EDIT: some things that I noticed that may be relevant.

  • I set the read timeout on the socket using setsockopts() , but set to 30 seconds. EAGAIN occur more than once every 30 seconds. CORRECTION My debugging was erroneous, EAGAIN does not happen as often as I thought. Perhaps this is a timeout run.

  • To connect, I want to have a connection timeout, so I temporarily disconnected the socket. This code is as follows:

     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, try to connect and select on the socket so that I can provide a timeout. Both calls to set and restore fcntl() return successfully, so after the completion of this function, the socket will end again in blocking mode.

+6
c ++ c linux sockets
source share
4 answers

Perhaps you have a non-zero receive timeout set on the socket (via setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,...) ), as this will also return EAGAIN

+19
source share

Is it possible that you are using MSG_DONTWAIT , being indicated as part of your flags? The man page indicates that EAGAIN will occur if data is not available and this flag is specified.

If you really want to block the block until recv() is successful, you can use the MSG_WAITALL flag.

+1
source share

I do not suggest this as a correction to the first attempt, but if you have all of the options, you can always select() on the socket with a timeout long enough to make it wait for data.

0
source share

EAGAIN generated by the OS almost like "Oh! I'm sorry to bother you." In case of this error you can try to read again. This is not a serious or fatal mistake. I have seen that these interruptions occur on Linux and LynxOS from one day to 100 times a day.

0
source share

All Articles