EAGAIN на recv () - PullRequest
       33

EAGAIN на recv ()

2 голосов
/ 24 января 2011

Я включил сокет-клиент для связи с ip-камерой по протоколу RTSP через HTTP для получения видео с камеры.

Чтобы установить связь с камерой, сначала я должен установить туннель HTTP-GET, а затем отправить команды RTSP. Когда камера теряет соединение, программа должна закрыть обработчик туннеля, завершить поток, и когда процесс вернется к основной функции, она начнет обмен данными (запуск протекторов и т. Д.).

При переподключении: туннель http-get установлен нормально, я имею в виду, сокет подключается и получает «HTTP OK», поэтому программа отправляет RTSP «DESCRIBE», но recv всегда возвращает ошибку EAGAIN. С помощью Wireshar я проверяю, что ответ DESCRIBE OK отправляется с камеры, но recv его не получает.

Вот код:

   struct sockaddr_in aServer;
  // string myData;
  char *myData=new char [256];
  connection *c=(connection*)vargp;


   memset(&aServer, 0, sizeof aServer);
   aServer.sin_family = AF_INET;

   aServer.sin_addr.s_addr = inet_addr(c->theServer.c_str());
   if (aServer.sin_addr.s_addr == INADDR_NONE)
   {
     struct hostent *hp;

     hp = gethostbyname(c->theServer.c_str());
     if (hp != NULL)
     {
       memcpy(&aServer.sin_addr, hp->h_addr, hp->h_length);
       aServer.sin_family = hp->h_addrtype;    //Protocol family
     }
     else
           cout << "Failed to resolve " << c->theServer.c_str()  << ": " << hstrerror(h_errno) << endl;
   }

   aServer.sin_port = htons(c->thePort);
   c->fd_get = socket(AF_INET, SOCK_STREAM, 0);

   struct timeval timeout;

   timeout.tv_sec = 5;
   timeout.tv_usec = 0;

  setsockopt(c->fd_get, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

   if (c->fd_get < 0){
    cout << "fd_get < 0"  << endl;
      c->bFin=true;
      c->WakeUP();
      }
   if (connect(c->fd_get, (struct sockaddr *) &aServer, sizeof aServer) < 0){
    cout << "connect fd_get < 0"  << endl;
    c->bFin=true;
    c->WakeUP();
   }
   if(!c->bFin){

    sprintf(myData, "GET %s HTTP/1.1\r\n", c->theURI.c_str());
    sprintf(myData, "%sx-sessioncookie: %s\r\nAccept: application/x-rtsp-tunnelled\r\nAuthorization: %s\r\n\r\n", myData,c->theHTTPSessionId.c_str(), c->addAuthorization(c->aGlobalUsername, c->aGlobalPassword).c_str() );

    cout << myData << endl;
    write(c->fd_get, myData, strlen(myData));

    //LISTENING...
    int theLen=1500; //3000;
    int ret=0;
    unsigned char datosRecibidos[3000];

    int flags =fctl(c->fd_get, F_GETFD;
    if((flags & O_NONBLOCK) == O_NONBLOCK){
        fprint(stderr, "yup, its nonblocking");
    }
    else{
        fprint(stderr, "nope, its blocking");
    }


    while (c->bFin==false){

     ret = read(c->fd_get, ReceivedData, theLen);
    // ret= recvfrom(c->fd_get, ReceivedData, theLen, 0,  (struct sockaddr *) 0, (socklen_t*)0);
     if (ret == 0)
     {
      cout << "Server closed connection: 0" << endl;

    }
      else
      if (ret == -1){
     fprintf (stderr, "\n[%d]: %s %d\n", __LINE__, strerror (errno), errno);

     if(errno==107 ||errno==EAGAIN){
      cout << "errno" << endl;
      c->bFin=true;
      c->WakeUP();
      cout << "vuelta wakeUP" << endl;
      break;// empezar de nuevo
     }else{
      cout << "errno" << endl;

     }

    }
    else{
     //cout << (string)ReceivedData[0]<< endl;
     c->ProcessReceivedData(ReceivedData, ret);
     usleep(10);
    }
   }

   close(c->fd_get);
   c->fd_get = -1;

   }

Может ли быть проблема тайм-аута? или проблема со стеком? Как я могу решить это?

Заранее спасибо за помощь. С наилучшими пожеланиями.

Кристина

Ответы [ 3 ]

4 голосов
/ 24 января 2011

EAGAIN означает, что нет данных, доступных для чтения на неблокирующем сокете. Итак, вы должны снова запустить вызов recv.

Вы на самом деле не опубликовали достаточно кода, чтобы предположить, что произошла программная ошибка, хотя могу ли я спросить, если вы обнаружите, что соединение закрыто, вы также закрываете свой конец перед тем, как все восстановить?

1 голос
/ 24 января 2011

Ваш сокет открыт в режиме O_NONBLOCK? Вы можете проверить это так:

int flags = fcntl(fd, F_GETFD);
if ((flags & O_NONBLOCK) == O_NONBLOCK) {
  fprintf(stderr, "Yup, it's nonblocking");
}
else {
  fprintf(stderr, "Nope, it's blocking.");
}

В неблокирующем режиме recv немедленно вернется с errno, установленным в EAGAIN, если еще нечего получить.

0 голосов
/ 29 июля 2013

Я бы всегда использовал poll () или select () перед каждой операцией чтения сокетов.

Также для проверки на отсутствие блокировки:

    int flags = fcntl(fd, F_GETFL, 0);
    if (flags & O_NONBLOCK) {
     fprintf(stderr, "Yup, it's nonblocking");
   } else {
    fprintf(stderr, "Nope, it's blocking.");
  }
...