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.
c ++ c linux sockets
Evan teran
source share