PDA

View Full Version : [C-Unix] Impostare timeout per ricezione pacchetti UDP


Alhazred
19-03-2014, 17:38
Mi trovo a dover imparare la programmazione C in ambiente Unix, nello specifico l'uso dei socket.

Un esercizio che sto svolgendo mi chiede di realizzare una funzione che prende in ingresso un unsigned che indichi un valore di timeout, una stringa che rappresenta un indirizzo IP ed un array null terminated contenente numeri di porte.
La funzione deve inviare un pacchetto UDP (di dimensione 1024 byte a contenuto nullo) a tutte le coppie IP-porta e poi mettersi in attesa di un qualsiasi pacchetto in risposta.
Se non riceve niente entro il timeout deve ritornare -1, altrimenti il numero di porta del processo che ha risposto per primo.

Il mio problema sta nell'impostare il timeout.

Ciò che ho scritto fin'ora è questo

#define BUFLEN 1024

int comUDP( unsigned timeout, char* ip, int ports[] )
{
int s_ds_sock, c_ds_sock;
struct sockaddr_in server_socket, client_socket;
char msg[BUFLEN] = NULL;

//creo il socket su cui il server riceverà i dati
s_ds_sock = socket (AF_INET, SOCK_DGRAM, 0);

server_socket.sin_family = AF_INET;
server_socket.sin_port = 2000;
server_socket.sin_addr.s_addr = INADDR_ANY;

bind (s_ds_sock, &server_socket, sizeof(server_socket));

int i = 0;

//finché ci sono unmeri di porta nell'array
while (ports[i] != NULL)
{
//creo il relativo socket
c_ds_sock = socket (AF_INET, SOCK_DGRAM, 0);

client_socket.sin_family = AF_INET;
client_socket.sin_port = ports[i];
client_socket.sin_addr = ip;

//invio il pacchetto
sendto (c_ds_sock, msg, BUFLEN, &client_socket, sizeof(client_socket));

//chiudo il socket col client
close(c_ds_socket);

//passo all'eventuale porta seguente
i++;
}

//qui dovrei fare il controllo sul timeout
if ( recvfrom (s_ds_socket, msg, BUFLEN, &server_socket, sizeof(server_socket)) !== -1 )
{

}
else
{

}

//chiudo il socket del server
close(s_ds_socket);
}

Come faccio ad impostare il timeout?

pabloski
19-03-2014, 18:54
Usa la funzione setsockopt e setta il valore dell'opzione SO_RCVTIMEO.

Si può circa così


struct timeval tout;
tout.tv_sec = 0;
tout.tv_usec = 500000;
if (setsockopt(s_ds_socket, SOL_SOCKET, SO_RCVTIMEO,&tout,sizeof(tout))<0) perror("Errore");


Ovviamente tv_sec è in secondi e tv_usec in microsecondi. Così puoi specificare un timer con una risoluzione elevata.

Le opzioni vanno settate prima della recvfrom e il branch else verrà eseguito se il timeout scaduto.

Alhazred
19-03-2014, 21:19
Grazie, quindi se ho ben capito dovrei avere una struttura così


if (setsockopt(...) < 0)
{
//c'è stato il timeot
}
else
{
//è arrivato un qualche dato ed eseguo la recvfrom(...)
}

giusto?

pabloski
19-03-2014, 21:34
no no, recvfrom andava benissimo dove stava

solo che prima di chiamare recvfrom, setti le opzioni del socket ( che in verità potresti settare pure dopo la chiamata a socket ) tramite la chiamata a setsockopt

Alhazred
20-03-2014, 15:53
Ah, ok, capito, grazie :)