读取套接字:EAGAIN:资源暂时不可用
Posted
技术标签:
【中文标题】读取套接字:EAGAIN:资源暂时不可用【英文标题】:Reading socket: EAGAIN: Resource temporarily unavailable 【发布时间】:2012-04-25 14:51:49 【问题描述】:我在 C++ 中创建了一个套接字,我需要它有一定的连接超时。这就是正在发生的事情:
创建套接字 使其成为 NON_BLOCKING 呼叫连接 它按预期返回 -1 和 errno EINPROGRESS 呼叫选择 返回 >0,因此已建立连接 再次使套接字阻塞这部分的代码如下:
bool mastControl::prepareSocket(char * address, int port, int * sockfd)
struct sockaddr_in serv_addr;
struct timeval timeout = 0,100000;
struct timeval connTimeout;
struct hostent * server = NULL;
fd_set socketSet;
socklen_t lon;
int sockOpt = 0;
long socketFlags = 0;
int buffersize = 8;
int res = 0;
int connectReturn = 0;
const int WAIT_TO_RECONN = 15;
server = gethostbyname(address);
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (*sockfd < 0)
qDebug()<<"Impossible to open socket: "<<strerror(errno);
return false;
if (server == NULL)
qDebug()<<"No such host: "<<strerror(h_errno);
return false;
// Initializating server direction struct:
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(port);
// Making socked non-blocking in order to set a timeout value for connection:
if((socketFlags = fcntl(*sockfd, F_GETFL, NULL)) < 0)
qDebug()<<"Impossible to retrieve sockets descriptor flags "<<strerror(errno);
return false;
socketFlags |= O_NONBLOCK;
if(fcntl(*sockfd, F_SETFL, socketFlags) <0)
qDebug()<<"Impossible to update sockets descriptor flags: "<<strerror(errno);
return false;
connectReturn = connect(*sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr));
if(connectReturn < 0)
if(errno == EINPROGRESS)
do
// Establishing a 15 seconds timeout:
connTimeout.tv_sec = 15;
connTimeout.tv_usec = 0;
FD_ZERO(&socketSet); // Initialising set of sockets as an empty set
FD_SET(*sockfd, &socketSet); // Adding socket to set
connectReturn = select(*sockfd+1, NULL, &socketSet, NULL, &connTimeout);
if(connectReturn<0 && errno!=EINTR) // Error in select
qDebug()<<"Connection error in select function: "<<strerror(errno);
return false;
else if(connectReturn>0) // Socket selected for writing
lon = sizeof(int);
if(getsockopt(*sockfd, SOL_SOCKET, SO_ERROR, (void*)(&sockOpt), &lon) <0)
qDebug()<<"Unnable to get socket options: "<<strerror(errno);
return false;
// Checking the value returned:
if(sockOpt)
qDebug()<<"Error in delayed connection: "<<strerror(errno);
return false;
break;
else // Timeout
qDebug()<<"Connection timeout exceeded: "<<strerror(errno);
return false;
while (1);
else
qDebug()<<"Connection error: "<<strerror(errno);
sleep(WAIT_TO_RECONN); // Wait 15 seconds
return false;
//Connected
// Must set the socket as blocking again:
if((socketFlags = fcntl(*sockfd, F_GETFL, NULL)) < 0)
qDebug()<<"Impossible to retrieve sockets descriptor flags "<<strerror(errno);
return false;
socketFlags &= (~O_NONBLOCK);
if(fcntl(*sockfd, F_SETFL, socketFlags) <0)
qDebug()<<"Impossible to update sockets descriptor flags "<<strerror(errno);
return false;
if (setsockopt (*sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
sizeof(timeout)) < 0)
qDebug()<< "ERR - setsockopt failed";
return false;
if (setsockopt (*sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
sizeof(timeout)) < 0)
qDebug()<< "ERR - setsockopt failed";
return false;
if ((res = setsockopt (*sockfd, SOL_SOCKET, SO_SNDBUF, &buffersize,
sizeof(buffersize))) == -1)
qDebug()<< "ERR - setsockopt failed (SO_SNDBUF) = " << res;
return false;
//Socket Ready
return true;
这行得通。但是然后我有一个循环,我正在调用一个函数来检查是否收到了要读取的新数据包:
bool mastControl::findPacket(int sockfd, st_messageMastToPc * messageReceived, bool * connected)
int n = 0;
bool messageFound = false;
char * buffer = (char *) messageReceived;
unsigned int pos = 0;
while ( ((n = read(sockfd, &(buffer[pos]), 1)) > 0) and not messageFound)
//qDebug() << "read output " << n;
if (n == 1)
pos++;
if ( (pos == 1) && (buffer[0] == 2))
// Some stuff...
else if ( (pos == 2) && (buffer[1] == 2) )
// Some stuff...
else if (pos >= uiMessageMastToPcSize)
messageFound = true;
//Complete message received
else if (pos < 2)
// Reseting pos
pos = 0;
if (n < 0)
qDebug()<< "Disconnected. Reason #" << errno << ": " << strerror(errno);
*connected = false;
return messageFound;
读取函数将 EAGAIN 设为 errno,表示“资源暂时不可用”。然后我假设我已断开连接,并且由于 boolean connected 现在为 false,在循环中我将尝试重新连接,再次创建套接字,依此类推。
所以,首先我不知道为什么会收到这个错误。
其次,我不知道是我完全断开连接,还是在这个错误之后创建新套接字时断开连接的人。
有什么帮助吗?
【问题讨论】:
【参考方案1】:EAGAIN
并不表示您已断开连接,它只是表示“现在没有可阅读的内容;稍后再试”。
您可以使用fcntl(2) 取消设置O_NONBLOCK
(使read
等到有可用的东西),或者在调用read
之前使用select(2) 之类的东西等待套接字。
编辑:现在您已经添加了更多代码,我可以看到您正在为套接字设置SO_RCVTIMEO
。这可能会导致阻塞 read
返回 EAGAIN
(因此,如果您不希望发生这种情况,只需将 SO_RCVTIMEO
单独留下)。
【讨论】:
好吧,这正是我所期待的。但正如我所说,我在选择后再次将套接字设置为 BLOCKING。这种做法有错吗?我是否需要在每次调用 read 之前调用 select ?有没有其他方法可以让 read 阻止执行,直到有东西要读? 您是如何将其设置为阻止模式的?你确定它发生在你打电话给read
之前吗?有SO_RCVTIMEO
设置吗?
我已经编辑了包括创建套接字并将其配置为再次阻塞的代码。它肯定发生在阅读之前。是的,正如您在函数末尾看到的那样,我正在设置 SO_RCVTIMEO (我以这种方式继承了它,但我认为它不起作用)。有错吗?
那么,我将擦除 SO_RCVTIMEO 就可以了?我无法理解这个问题,因为看起来为 RCV 超时设置的 timeval 是 10 秒,不是吗?
SO_SNDTIMEO 也会影响写函数吗?那么 SO_SNDBUF 呢?以上是关于读取套接字:EAGAIN:资源暂时不可用的主要内容,如果未能解决你的问题,请参考以下文章
UDP和套接字,recvfrom()返回-1,资源暂时不可用
C 套接字服务器和 Python 套接字客户端“资源暂时不可用”