2009-12-01 16 views
14

Estoy tratando de establecer un socket de bloqueo de tiempo de espera después de 16 m de intentar recvfrom() en un puerto. La plataforma es Windows. He visto toneladas de ejemplos en línea y parece realmente simple, parece que no puedo hacer que funcione. ¡Cualquier ayuda sería apreciada!tiempo de espera para recvfrom Winsock

#include <winsock2.h> 
#include <string> 

#pragma comment(lib, "ws2_32.lib") 

#define PORT_NUM 8001 

int main(void) 
{ 
    std::string localIP; 
    sockaddr_in localAddr; 
    sockaddr_in remoteAddr; 
    hostent* localhost; 
    char buffer[1024]; 
    WSADATA wsData; 

    int result = WSAStartup(MAKEWORD(2,2), &wsData); // winsock version 2 

    localhost = gethostbyname(""); 
    localIP = inet_ntoa(*(in_addr*)*localhost->h_addr_list); 

    localAddr.sin_family  = AF_INET; 
    localAddr.sin_port   = htons(PORT_NUM);    // Set Port Number 
    localAddr.sin_addr.s_addr = inet_addr(localIP.c_str()); // Set IP Address 

    int mHandle = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0); 

    if(mHandle == INVALID_SOCKET) 
    return 1; 


    if(bind(mHandle, (SOCKADDR*)&localAddr, sizeof(localAddr)) == SOCKET_ERROR) 
    return 1; 

    timeval tv; 
    tv.tv_sec = 0; 
    tv.tv_usec = 1600; 

    // Set Timeout for recv call 
    if(setsockopt(mHandle, SOL_SOCKET, SO_RCVTIMEO, 
       reinterpret_cast<char*>(&tv), sizeof(timeval))) 
    return 1; 

    int length = sizeof(remoteAddr); 

    // <-- Blocks here forever 
    recvfrom(mHandle, buffer, 1024, 0, (SOCKADDR*)&remoteAddr, &length); 

    return 0; 
} 

/* I've also tried passing the time like so: 
int ms = 16; 

if(setsockopt(mHandle, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char*>(&ms), sizeof(int))) 
    return 1; */ 
+0

SO_RCVTIMEO no es muy portable - qué plataforma está usando? – Dipstick

+8

Probablemente quiera usar la función 'seleccionar' – laura

+0

¡Hola, gracias! ¡Sí, busqué en select y lo hice funcionar! –

Respuesta

21

Miré en la función de selección y como Laura me dijo que debía hacer y lo tiene que trabajar muy fácilmente! ¡Gracias!

fd_set fds ; 
int n ; 
struct timeval tv ; 

// Set up the file descriptor set. 
FD_ZERO(&fds) ; 
FD_SET(mHandle, &fds) ; 

// Set up the struct timeval for the timeout. 
tv.tv_sec = 10 ; 
tv.tv_usec = 0 ; 

// Wait until timeout or data received. 
n = select (mHandle, &fds, NULL, NULL, &tv) ; 
if (n == 0) 
{ 
    printf("Timeout..\n"); 
    return 0 ; 
} 
else if(n == -1) 
{ 
    printf("Error..\n"); 
    return 1; 
} 

int length = sizeof(remoteAddr); 

recvfrom(mHandle, buffer, 1024, 0, (SOCKADDR*)&remoteAddr, &length); 
+0

Entonces, lo que entiendo es que le envía solo un paquete cada vez que ejecuta su aplicación. Supongamos que está enviando miles de paquetes dentro de un bucle, ¡este código puede bloquearse! ¿Cómo resolverás ese problema? –

+0

Esta es la mejor respuesta. La otra respuesta, SO_RCVTIMEO como DWORD, excederá el tiempo de espera de recvfrom, pero tiene algunos problemas: 1) si el tiempo de espera ocurre, socket ya no está en un estado válido. 2) No pude encontrar ningún documento de Windows que explicara cómo agotar el tiempo de espera ... pero como su socket se invalidará, supongo que tendrá que crear uno nuevo de todos modos. –

1

Supongo que Windows de la llamada WSASocket(). Si es así, está pasando el tiempo de espera incorrectamente.

MSDN dice que SO_RCVTIMEO toma un parámetro int que especifica el tiempo de espera en ms.

+0

También lo he probado pasándolo de la siguiente manera: int ms = 16; if (setsockopt (mHandle, SOL_SOCKET, SO_RCVTIMEO, reinterpretar_cast (y ms), sizeof (int))) return 1; Todavía tengo el mismo resultado ... –

+0

Gracias, esto es justo lo que necesitaba para un sistema de socket BSD que no acepta el SO_RCVTIMEO –

+0

También dice "Si una llamada de recepción de bloqueo expira, la conexión está en un estado indeterminado y debe ser cerrado. Si el socket se crea utilizando la función WSASocket, entonces el parámetro dwFlags debe tener el atributo WSA_FLAG_OVERLAPPED establecido para el tiempo de espera para que funcione correctamente. de lo contrario, el tiempo de espera no entra en vigor. ", así que no estoy seguro de si que se va a utilizar con regularidad ... – Marki555

10

Windows: valor de tiempo de espera es un DWORD en milisegundos, dirección pasada a setsockopt() es const char *

LINUX: valor de tiempo de espera es un timeval struct, dirección pasada a setsockopt() es const void *

Fuente: http://forums.codeguru.com/showthread.php?t=353217

13

lo probé pasándolo como el folloing

 int iTimeout = 1600; 
    iRet = setsockopt(pSapManager->m_cSocket, 
         SOL_SOCKET, 
         SO_RCVTIMEO, 
         /* 
         reinterpret_cast<char*>(&tv), 
         sizeof(timeval)); 
         */ 
         (const char *)&iTimeout, 
         sizeof(iTimeout)); 

y ejecútelo !!

+0

Hola, bienvenido a SO. Intenta explicar tu respuesta en palabras, no solo en el código.Será más fácil para todos aprender de esa manera. Además, dado que está respondiendo una vieja pregunta, ¿cómo difiere su respuesta de las otras respuestas? –