【问题标题】:Timeout on recvfrom ( winsock2 & udp )recvfrom 超时(winsock2 和 udp)
【发布时间】:2014-07-01 09:36:43
【问题描述】:

我正在尝试在 recvfrom() 函数上实现 timeout

为此,我使用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;
    }
}

【问题讨论】:

  • 你不检查select是否返回-1。添加类似int retval = select(...) ; 的内容,如果retval == -1 则查看errno,就像在man 示例中一样:linux.die.net/man/2/select
  • 完成但没有改变任何东西,我会更新我的帖子
  • 你在socket上设置了非阻塞模式吗?
  • 它在哪里崩溃? buffer 是如何声明的?
  • 为什么每次调用这个方法都要打开和关闭一个socket?您应该在应用程序的整个生命周期内保持套接字打开。按照您的方式,您有丢失数据的重大风险。

标签: c++ c udp winsock2


【解决方案1】:

感谢您的帮助,问题是:这个程序循环运行,所以我在错误的时间打开和关闭了套接字。

【讨论】:

    猜你喜欢
    • 2016-01-09
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-08
    • 2015-05-23
    • 2012-02-13
    相关资源
    最近更新 更多