C++ 读取套接字:EAGAIN:资源暂时不可用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10318191/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reading socket: EAGAIN: Resource temporarily unavailable
提问by Roman Rdgz
I have created a socket in C++ and I needed it to have certain connection timeout. So that's what is happening:
我在 C++ 中创建了一个套接字,我需要它有一定的连接超时。所以这就是正在发生的事情:
- Create socket
- Make it NON_BLOCKING
- Call connect
- It returns -1 and errno EINPROGRESS as expected
- Call select
- Returns >0, so connection has been made
- Make the socket BLOCKING again
- 创建套接字
- 使其成为 NON_BLOCKING
- 呼叫连接
- 它按预期返回 -1 和 errno EINPROGRESS
- 呼叫选择
- 返回 >0,所以连接已经建立
- 再次使套接字阻塞
Code for this part is the following:
这部分的代码如下:
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;
}
That works ok. But then I have a loop where I'm calling a function which checks if there is a new packet received to read:
这工作正常。但是后来我有一个循环,我正在调用一个函数来检查是否收到了要读取的新数据包:
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;
}
Read function is giving EAGAIN as errno, which means "Resource temporarily unavailable". Then I'm supposing I am disconnected, and since boolean connected is now false, in the loop I will be trying to reconnect creating the socket again, ans so on.
读取功能将 EAGAIN 作为 errno,这意味着“资源暂时不可用”。然后我假设我已断开连接,并且由于 boolean connected 现在为 false,因此在循环中我将尝试重新连接,再次创建套接字,等等。
So, in the first place I don't know why I'm receiving this error.
所以,首先我不知道为什么我会收到这个错误。
In the second place, I don't know if I am disconnected at all, or it's me the one who is disconnecting when creating the new socket after this error.
其次,我不知道我是否完全断开连接,或者是我在此错误后创建新套接字时断开连接。
Any help?
有什么帮助吗?
回答by James McLaughlin
EAGAIN
does not mean you're disconnected, it just means "there's nothing to read now; try again later".
EAGAIN
并不意味着您已断开连接,它只是意味着“现在没有什么可阅读的;稍后再试”。
You could either unset O_NONBLOCK
with fcntl(2)(making read
wait until there's something available), or just wait on the socket with something like select(2)before calling read
.
你既可以未设置O_NONBLOCK
与的fcntl(2) (使read
等待,直到有可用的东西),或只是等待插槽上的东西,如选择(2)调用之前read
。
EDIT: Now that you've added more code, I can see that you're setting SO_RCVTIMEO
for the socket. This can cause a blocking read
to return EAGAIN
(so if you don't want that to happen, simply leave SO_RCVTIMEO
alone).
编辑:现在您已经添加了更多代码,我可以看到您正在SO_RCVTIMEO
为套接字设置。这可能会导致阻塞read
返回EAGAIN
(因此,如果您不希望发生这种情况,请不要SO_RCVTIMEO
理会)。