Тайм-аут при получении (winsock2 и udp)

Я пытаюсь реализовать timeout в функции recvfrom().

Для этого я использую функцию select(). Я беру код из большого интернета, но не знаю почему, моя программа вылетает, когда я ее использую. Я запускаю этот сервер в сети, если это может помочь. Вот что я пытаюсь сделать:

...
        // Setup timeval variable
        timeval timeout;
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;

        // Setup fd_set structure
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(id_de_la_socket, &fds);

        // Return value:
        // -1: error occurred
        // 0: timed out
        // > 0: data ready to be read
        int retval = select(id_de_la_socket+1, &fds, NULL, NULL, &timeout);
        if(retval == -1){
            printf("Error");
            return NULL;
        }
        else if(retval == 0){
            printf("Timeout");
            return NULL;
        }
        else{
            nombre_de_caractere=recvfrom(id_de_la_socket,buffer,1515,/*MSG_PARTIAL*/0,(struct sockaddr*)&information_sur_la_source,&tempo);
...

До попытки реализовать timeout все работало нормально, мой recvfrom() был в блочном режиме. Поэтому я думаю, что проблема связана с этим кодом, который я добавляю. Может быть, это параметр функции, которую я плохо понимаю.

Спасибо за вашу помощь.

РЕДАКТИРОВАТЬ: Полный код:

#include "serveur.h"
#include <unistd.h>
#include <fcntl.h>
serveur::serveur()
{
}

StructureSupervision::T_StructureSupervision* serveur::receiveDataUDP(){
    WSADATA initialisation_win32;
    int erreur; 
    int tempo; 
    int nombre_de_caractere; 
    char buffer[65535]; 
    SOCKET id_de_la_socket; 
    SOCKADDR_IN information_sur_la_source; 

    erreur=WSAStartup(MAKEWORD(2,2),&initialisation_win32);
    if (erreur!=0)
        printf("\nDesole, je ne peux pas initialiser Winsock du a l'erreur : %d %d",erreur,WSAGetLastError());
    else
        printf("\nWSAStartup  : OK");


    id_de_la_socket=socket(AF_INET,SOCK_DGRAM,0);
    if (id_de_la_socket==INVALID_SOCKET)
        printf("\nDesole, je ne peux pas creer la socket du a l'erreur : %d",WSAGetLastError());
    else
        printf("\nsocket      : OK");


    information_sur_la_source.sin_family=AF_INET;
    information_sur_la_source.sin_addr.s_addr = inet_addr("10.100.13.129"); // Ecoute sur toutes les IP locales
    information_sur_la_source.sin_port=htons(4000); // Ecoute sur le port 4000
    erreur=bind(id_de_la_socket,(struct sockaddr*)&information_sur_la_source,sizeof(information_sur_la_source));
    if (erreur!=0)
        printf("\nDesole, je ne peux pas ecouter ce port : %d %d",erreur,WSAGetLastError());
    else
        printf("\nbind        : OK \n");


    tempo=sizeof(information_sur_la_source); // Passe par une variable afin d'utiliser un pointeur

    // Setup timeval variable
    timeval timeout;
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;
    // Setup fd_set structure
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(id_de_la_socket, &fds);
    // Return value:
    // -1: error occurred
    // 0: timed out
    // > 0: data ready to be read
    ULONG NonBlock = 1; ioctlsocket(id_de_la_socket, FIONBIO, &NonBlock);
    int retval = select(id_de_la_socket+1, &fds, NULL, NULL, &timeout);
    if(retval == -1){
        printf("Error");
        return NULL;
    }
    else if(retval == 0){
        printf("Timeout");
        return NULL;
    }
    else{
    nombre_de_caractere=recvfrom(id_de_la_socket,buffer,1515,/*MSG_PARTIAL*/0,(struct sockaddr*)&information_sur_la_source,&tempo);
    buffer[nombre_de_caractere]=0; // Permet de fermer le tableau apr�s le contenu des data, car la fonction recvfrom ne le fait pas
    //printf("\nVoici les donnees : %s",buffer);
    StructureSupervision::T_StructureSupervision *structureReception = (StructureSupervision::T_StructureSupervision *) buffer;
    std::cout << "Voici le numero de Statut Ground Flight : " << structureReception->SystemData._statutGroundFlight;


    erreur=closesocket(id_de_la_socket);
    if (erreur!=0)
        printf("\nDesole, je ne peux pas liberer la socket du a l'erreur : %d %d",erreur,WSAGetLastError());
    else
        printf("\nclosesocket : OK");

    // ********************************************************
    // Quitte proprement le winsock ouvert avec la commande WSAStartup
    // ********************************************************
    erreur=WSACleanup(); // A appeler autant de fois qu'il a �t� ouvert.
    if (erreur!=0)
        printf("\nDesole, je ne peux pas liberer winsock du a l'erreur : %d %d",erreur,WSAGetLastError());
    else
        printf("\nWSACleanup  : OK");

    return structureReception;
    }
}

person Evans Belloeil    schedule 01.07.2014    source источник
comment
Вы не проверяете, возвращает ли select -1. Добавьте что-то вроде int retval = select(...) ; и посмотрите на errno if retval == -1, как в примере с человеком: linux.die.net /man/2/выбрать   -  person Holt    schedule 01.07.2014
comment
Сделано, но ничего не изменилось, я обновлю свой пост   -  person Evans Belloeil    schedule 01.07.2014
comment
Вы установили неблокирующий режим на сокете?   -  person Holt    schedule 01.07.2014
comment
@Holt Ну нет, зачем мне это делать?   -  person Evans Belloeil    schedule 01.07.2014
comment
Не профессионал в select, но просматривая примеры Google с сокетом, я нашел это winsocketdotnetworkprogramming.com/winsock2programming/, немного отвратительно, но с использованием неблокирующего сокета, поэтому просто интересно, может ли это быть причиной сбоев. Может быть, вам стоит проверить и посмотреть, что произойдет.   -  person Holt    schedule 01.07.2014
comment
Где происходит сбой? Как объявляется buffer?   -  person unwind    schedule 01.07.2014
comment
@unwind buffer[nombre_de_caractere]=0;   -  person Evans Belloeil    schedule 01.07.2014
comment
@EvansBelloeil Итак, каково значение nombre_de_caractere перед вызовом recvfrom()? Вы заменяете это значение возвращаемым значением recvfrom(), что звучит немного пугающе.   -  person unwind    schedule 01.07.2014
comment
@unwind Раньше значения не было, это инициализация, но она хорошо работает без тайм-аута ...   -  person Evans Belloeil    schedule 01.07.2014
comment
@Holt Использование неблочного режима мне не кажется хорошим, я боюсь потерять информацию :/   -  person Evans Belloeil    schedule 01.07.2014
comment
@EvansBelloeil Итак, у вас есть, например. int nombre_de_caractere; char buffer[nombre_de_caractere] = 0;? Если да, то можете ли вы обнаружить там проблему?   -  person unwind    schedule 01.07.2014
comment
@unwind Ну нет, если он идет в другом, nombre_de_caractere должен быть равен › 0.   -  person Evans Belloeil    schedule 01.07.2014
comment
@EvansBelloeil Почему вы теряете информацию в неблокирующем режиме?   -  person Holt    schedule 01.07.2014
comment
@Holt Да, может быть, вы знаете, как перевести свой сокет в неблокирующий режим?   -  person Evans Belloeil    schedule 01.07.2014
comment
На винде по моей предыдущей ссылке думаю: ULONG NonBlock = 1; ioctlsocket(ListenSocket, FIONBIO, &NonBlock); и проверить возврат ioctlsocket с SOCKET_ERROR на ошибку.   -  person Holt    schedule 01.07.2014
comment
Вы должны инициализировать переменную темпа.   -  person harper    schedule 01.07.2014
comment
В предыдущем комментарии вы написали Нет значения перед вопросом Каково значение nombre_de_charactere перед вызовом recvfrom? Этот номер важен для распределения buffer. Когда есть неопределенное значение, у вас неопределенное поведение. Ваша версия без select просто случайно работает. nombre_de-charactere ДОЛЖЕН быть 1515 или выше. Если это не выполняется, вы можете получить переполнение буфера.   -  person harper    schedule 01.07.2014
comment
Я обновлю свой пост прямо сейчас, предоставив свой полный код сервера и объяснив, что я запускаю его в потоке.   -  person Evans Belloeil    schedule 01.07.2014
comment
Хорошо, я понял, что не так, проблема в том, что я вызываю эту функцию в цикле while(1) и неправильно закрываю порт, я скоро отвечу на свой пост, всем спасибо, ваш комментарий заставил меня дважды подумать: )   -  person Evans Belloeil    schedule 01.07.2014
comment
@EvansBelloeil, эта штука с id_de_la_socket... select() ожидает там тип int, а id_de_la_socket объявлен как тип SOCKET... не уверен, что это проблема, но просто перепроверить...   -  person wick    schedule 01.07.2014
comment
Зачем открывать и закрывать сокет каждый раз, когда вызывается этот метод? Вы должны держать сокет открытым на протяжении всего срока службы приложения. Ваш путь у вас есть большой риск потери данных.   -  person user207421    schedule 02.07.2014


Ответы (1)


Спасибо за вашу помощь, проблема заключалась в следующем: эта программа работает в цикле, поэтому я открывал и закрывал сокет в неподходящее время.

person Evans Belloeil    schedule 02.07.2014