读取套接字:EAGAIN:资源暂时不可用 [英] Reading socket: EAGAIN: Resource temporarily unavailable

查看:226
本文介绍了读取套接字:EAGAIN:资源暂时不可用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在C ++中创建了一个套接字,我需要它有一定的连接超时。这是发生了什么:




  • 创建套接字

  • 将其设为NON_BLOCKING

  • 呼叫连接

  • 按预期返回-1和errno EINPROGRESS

  • 呼叫选择

  • 返回> 0,因此已建立连接

  • 再次创建套接字BLOCKING



该部分如下:

  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()<<不可能打开套接字:<< strerror(errno);
return false;
}

if(server == NULL){
qDebug()<<No such host:<< strerror(h_errno);
return false;
}

//初始化服务器方向结构:
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);

//进行socked非阻塞以设置连接的超时值:
if((socketFlags = fcntl(* sockfd,F_GETFL,NULL))< 0){
qDebug()<<不可能检索套接字描述符标志<< strerror(errno);
return false;
}
socketFlags | = O_NONBLOCK;
if(fcntl(* sockfd,F_SETFL,socketFlags)< 0){
qDebug()<不可能更新套接字描述符标记:< strerror(errno);
return false;
}

connectReturn = connect(* sockfd,(struct sockaddr *)& serv_addr,sizeof(serv_addr));
if(connectReturn< 0){
if(errno == EINPROGRESS){
do {
//建立15秒超时:
connTimeout.tv_sec = 15;
connTimeout.tv_usec = 0;
FD_ZERO(& socketSet); //将套接字初始化为空集
FD_SET(* sockfd,& socketSet); // add socket to set
connectReturn = select(* sockfd + 1,NULL,& socketSet,NULL,& connTimeout);
if(connectReturn <0&& errno!= EINTR){// select in
中的错误qDebug()<<选择函数中的连接错误:< );
return false;
}
else if(connectReturn> 0){//编写$ Socket选择
lon = sizeof(int);
if(getsockopt(* sockfd,SOL_SOCKET,SO_ERROR,(void *)(& sockOpt),& lon)< 0){
qDebug()< options:<< strerror(errno);
return false;
}
//检查返回值:
if(sockOpt){
qDebug()<<延迟连接中出错:< );
return false;
}
break;
}
else {// Timeout
qDebug()<<超过连接超时:<< strerror(errno);
return false;
}
} while(1);
}
else {
qDebug()<<Connection error:<< strerror(errno);
sleep(WAIT_TO_RECONN); //等待15秒
return false;
}
}

//已连接

//必须再次设置套接字为阻塞:
if((socketFlags = fcntl * sockfd,F_GETFL,NULL))<0){
qDebug()<不可能检索套接字描述符标志<< strerror(errno);
return false;
}
socketFlags& =(〜O_NONBLOCK);
if(fcntl(* sockfd,F_SETFL,socketFlags)<0){
qDebug()<<不可能更新套接字描述符标志<
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;
}
//套接字准备

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)而不是messageFound){

// qDebug ()<< 读取输出< 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;
//完成消息接收
} else if(pos <2){
//重新连接pos
pos = 0;
}
}
}

if(n <0){
qDebug()< 已断开连接。原因#<< errno<< :<< strerror(errno);
* connected = false;
}

return messageFound;
}

读取函数将EAGAIN赋值为errno,表示资源暂时不可用。然后我假设我断开连接,并且由于布尔连接现在是假,在循环中我将尝试重新连接创建套接字,再次,等等。



所以,首先,我不知道为什么我收到这个错误。



第二,我不知道我是否断开连接



任何帮助?

解决方案

EAGAIN 并不意味着你断开连接,它只是意味着现在没有什么可阅读; p>

您可以使用 O_NONBLOCK / fcntl> fcntl(2)(使等待有可用的东西),或者只是在套接字上等待 select(2),然后调用



EDIT:现在您已经添加了更多代码,我可以看到您为套接字设置 SO_RCVTIMEO 。这可能导致阻塞读取返回 EAGAIN (所以如果你不想发生这种情况,只需离开 SO_RCVTIMEO 单独)。


I have created a socket in C++ and I needed it to have certain connection timeout. So that's what is happening:

  • 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

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.

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?

解决方案

EAGAIN does not mean you're disconnected, it just means "there's nothing to read now; try again later".

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.

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).

这篇关于读取套接字:EAGAIN:资源暂时不可用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆