简体   繁体   English

读取套接字:EAGAIN:资源暂时不可用

[英]Reading socket: EAGAIN: Resource temporarily unavailable

I have created a socket in C++ and I needed it to have certain connection timeout. 我用C ++创建了一个套接字,我需要它才能有一定的连接超时。 So that's what is happening: 这就是发生的事情:

  • Create socket 创建套接字
  • Make it NON_BLOCKING 让它成为NON_BLOCKING
  • Call connect 呼叫连接
  • It returns -1 and errno EINPROGRESS as expected 它按预期返回-1和errno EINPROGRESS
  • Call select 呼叫选择
  • Returns >0, so connection has been made 返回> 0,因此已建立连接
  • 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". 读取功能将EAGAIN设为errno,表示“资源暂时不可用”。 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". 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 . 您可以使用fcntl(2)取消设置O_NONBLOCK (使read等待直到有可用的东西),或者在调用read之前在select(2)之类的套接字上等待。

EDIT: Now that you've added more code, I can see that you're setting SO_RCVTIMEO for the socket. 编辑:现在您已经添加了更多代码,我可以看到您正在为套接字设置SO_RCVTIMEO This can cause a blocking read to return EAGAIN (so if you don't want that to happen, simply leave SO_RCVTIMEO alone). 这可能导致阻塞read返回EAGAIN (因此,如果您不希望发生这种情况,只需单独留下SO_RCVTIMEO )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM