2012-04-25 6 views
3

私はC++でソケットを作成しましたが、特定の接続タイムアウトが必要でした。だから、何が起こっているかです:ソケットを読み込み中:EAGAIN:リソースが一時的に利用できない

  • それはそれは-1を返し、errnoにEINPROGRESSとして期待
  • コールがそう
  • 戻り値> 0を、選択
  • を接続
  • コールをNON_BLOCKING作るソケット
  • を作成します。接続が完了しました
  • ソケットをもう一度ブロックします
[OK]を作品

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; 
} 

読む機能はerrnoをとしてEAGAINを与えている、「リソース一時的に利用できない」を意味します。私は、新しいパケットを読み取るために受け取っているかどうかを確認する関数を呼び出すよどこでも、私はループを持っています。それから私は、私は切断されていると仮定しているので、ブール値の接続が今や偽である、私は再びソケットを作成するために再接続しようとしているループで、そうです。

私はなぜこのエラーを受けているのか分かりません。

2つ目は、接続が完全に切断されているか、このエラーの後に新しいソケットを作成するときに切断されているのかどうかわかりません。

助けが必要ですか?

答えて

8

EAGAINあなたが切断されているという意味ではなく、「今すぐ読むことはできません。後でやり直してください」という意味です。

は、次のいずれかの設定を解除 O_NONBLOCK fcntl(2)で(利用可能なものがありますまで read待機させる)、または単に readを呼び出す前に select(2)のようなものでソケットに待つことができます。

EDIT:コードを追加したので、ソケットにSO_RCVTIMEOを設定しています。これにより、ブロックreadEAGAINを返す可能性があります(そうしたくない場合は、単にSO_RCVTIMEOのままにしてください)。

+0

これは私が期待していたものです。しかし、私が言ったように、私は選択後にソケットを再びBLOCKINGに設定しました。その練習は間違っている?毎回読んだ後にselectを呼び出す必要がありますか?読んで何かがあるまで実行をブロックする他の方法はありませんか? –

+0

どのようにブロックモードに設定しましたか? 'read'を呼び出す前に起こったと確信していますか? 'SO_RCVTIMEO'セットはありますか? –

+0

私は、ソケットを作成するコードを含めて編集し、再度ブロックするように設定しました。それは確かに読む前に起こります。関数の最後に表示されるように、私はSO_RCVTIMEOを設定しています(私はそれを継承していますが、うまくいきません)。それは間違っていますか? –

関連する問題