Newsgroup: it.comp.os.linux.development
Titolo: Timeout con le socket

Sto implementando un protocollo stop and wait , quindi :
per ogni pacchetto che invio ,se entro un tot di tempo non viene
confermato da un ack, deve essere rispedito , altrimenti si passa al
successivo.
Ho dato una occhiata ai timer del C ,ma non ho capito bene come
implementare questa funzione ,anche perche' il tempo di attesa e' in
secondi e considerando che il mio protocollo gira su ethernet da 100 Mbit
mi sembra un tempo troppo elevato.
-- 
Ciao Flex
[X contattarmi togli NONSPAMM RE dall'indirizzo Per SPAM scrivete a: /dev/null]
________________________________________________
Chi sa ascoltare non solo è simpatico a tutti ,
ma prima o poi finisce con l'imparare qualcosa


man select
Gia' che ci sei vedi anche:
man fnctl (flag O_NONBLOCK)
man usleep
man gettimeofday
Alessandro.



Ottimo mi hai illuminato e ci sono anche i ns e gli us :-)
Potresti consigliarmi un valore veritiero da impostare ad un timer di
una ethernet prima di rispedire il pacchetto ?



Dipende dall'applicazione, se devi semplicemente trasferire dati il timeout
puo' essere relativamente alto (per esempio da 0,5 a 2,0 secondi) vista la
bassa probabilita' di perdita di pacchetti (a meno che non si scolleghi il
cavo di rete :-), se la comunicazione deve essere in "rempo reale" (tipo
giochi d'azione o simulatori) questi valori sono troppo alti. 
In caso di applicazioni interattive a volte si sceglie di non 
ritrasmettere affatto perche' ogni pacchetto contiene lo stato corrente
e quelli intermedi possono essere scartati (quasi) senza problemi (succede
nei giochi quando un personaggio sparisce dal campo di gioco per riapparire
in un'altra zona dopo qualche secondo.
Alessandro.

 Ottimo mi hai illuminato e ci sono anche i ns e gli us :-)
Tieni conto pero' che in linux non puoi avere una risoluzione temporale 
minore di 10ms (almeno in user space).
Ciao,
Stefano.

 
Ho scritto la seguente procedura che si mette in attesa di un pacchetto
contenente un ack , soltato che mi funziona solo la prima volta che la
invoco , che sbaglio madornale avro' fatto ?
// Ritorna il PackNumber se arriva correttamente l'ack -1 altrimenti
int Wait_Ack(int sockfd,int PackNumber)
{
char packet[PACKET_SIZE] ;
fd_set fd_read ; // Info sui Socket
struct timeval timeout, *timer ;
timeout.tv_sec  =  SEC_LATE ;
timeout.tv_usec = USEC_LATE ;
timer = &timeout ;
FD_ZERO(&fd_read);
FD_SET(sockfd,&fd_read);
if (select(sockfd+1,&fd_read,0,0,timer) < 0) error("Errore nel socket\n") ;
if (FD_ISSET(sockfd,&fd_read)) {
       if ( (recvfrom(sockfd, packet,sizeof(packet), 0, (struct sockaddr *) &saddr, &saddr_len)) < 0 )
	       printf("Errore  nella recvfrom \n");
       else
           if ( (packet[0] == ACK) && (packet[1] == PackNumber ) ) ;
           else PackNumber = -1 ;
       }        
 
else PackNumber =  -1 ; // Caso che si verifica	 
return  PackNumber ;
}
Sembrerebbe che non arrivi nessun pacchetto , ma la cosa e' strana


 Sembrerebbe che non arrivi nessun pacchetto , ma la cosa e' strana
Invece si , il problema era nella send , adesso funziona , cmq se hai
suggerimenti sono ben accetti




Se usi /dev/rtc la risoluzione puo` essere nettamente superiore. C'e` un
esempio in Documentation/rtc.txt nei sorgenti del kernel.
Ciao
Simone

Dunque, io ho fatto un programma (funziona solo su ambienti Unix, visto che
usa l'header <sys/socket.h>) che controlla lo stato di un host su una
determinata porta.
Io mando come argomenti al programma il nome dell'host e il numero della
porta, e il programma mi ritorna una frase del tipo "l'host è online" oppure
"l'host è offline".
Per esempio se il mio programma si chiama "controlla_host" e se digito:
/home/piero/controlla_host localhost 21
Lui mi ritorna come output "L'host è online", in quanto ho un server FTP
attivo in quel momento.
Ma se digito un host o un IP preso a caso, il programma invece di ritornarmi
"l'host è offline", non mi ritorna niente. Penso che bisognerebbe settare
correttamente il timeout della socket, ma non ho trovato niente al riguardo
con google...
Riporto la funzione che uso per controllare lo stato dell'host...
Dove target è un host e port un numero di porta.
int get_tcp(int port, char *target){
 struct sockaddr_in client;
 struct hostent *hostinfo;
 int sock;
 if ((sock=socket(AF_INET, SOCK_STREAM, 0))==-1){
  printf("Error when trying to load the socket.\n");
 }else {
  client.sin_family=AF_INET;
  hostinfo=gethostbyname(target);
  client.sin_addr=*((struct in_addr *) hostinfo->h_addr);
  client.sin_port=htons(port);
  if (connect(sock,(struct sockaddr*) &client, sizeof(client))==0)
printf("L'host è online!");
 }
 close (sock);
 return 1;
}
Grazia in anticipo per qualsiasi aiuto.
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/


Devi usare fcntl() per impostare il flag O_NONBLOCK sul socket e poi andare
di select().
Alessandro.

 Alessandro.
Ehm... io ho provato ad usare le funzioni che mi hai detto, ma non ci sono
riuscito. Con le prove che sono riuscito a fare, mi ritorna che un host è
sempre online anche quando non lo è.
Posto le funzioni che ho provato... send_img è una funzione che manda un
immagine come output e ONLINE e OFFLINE sono due valori dichiarati con
#define.
int check_tcp(int port, char *target){
 struct sockaddr_in client;
 struct hostent *hostinfo;
 int sock, flags;
 if ((sock=socket(AF_INET, SOCK_STREAM, 0))==-1){
  printf("Error when trying to load the socket.\n");
 }else {
  if((flags=fcntl(sock,F_GETFL,0))<0) send_img(OFFLINE);
  flags |= O_NONBLOCK;
  if (fcntl(sock,F_SETFL,flags)<0) send_img(OFFLINE);
  client.sin_family=AF_INET;
  if ((hostinfo=gethostbyname(target))==NULL) send_img(OFFLINE);
  client.sin_addr=*((struct in_addr *) hostinfo->h_addr);
  client.sin_port=htons(port);
  try_sock(sock, &client);
 }
 close (sock);
 return 1;
}
int try_sock(int sock, struct sockaddr client){
  struct timeval timeout;
  fd_set fdset;
  int ns;
  timeout.tv_sec = 1000;
  timeout.tv_usec = 1000;
  FD_ZERO(&fdset);
  FD_SET(sock, &fdset);
  connect(sock,(struct sockaddr*) &client, sizeof(client));
  ns=select(sock+1, &fdset, NULL, NULL, &timeout);
  if (!ns) send_img(OFFLINE);
  else send_img(ONLINE);
 return 1;


   if (!ns) send_img(OFFLINE);
Meglio:
if (ns>0) send_img(OFFLINE);
Alessandro.


Hem,
if (ns<=0) send_img(OFFLINE);
Alessandro.


Ricapitoliamo un po'...
Il programma ritorna "online" quando:
l'host è un indirizzo della rete locale e la porta specificata è aperta.
l'host è un indirizzo internet e la porta specificata è aperta.
Il programma ritorna "offline" quando:
l'host è un indirizzo della rete locale e la porta specificata è chiusa.
l'host è un indirizzo non valido.
Il programma attende inutilmente quando:
l'host è un indirizzo internet valido e la porta specificata è chiusa.
Questo ultimo punto dev'essere cambiato con un messaggio di offline.
Pensavo che con il timeout avrei risolto, ma invece non ha funzionato.
Qualcuno può aiutarmi?
l'hos


Tutto risolto.
Posto la fuzione completa
dove send_img è una funzione che ritorna un valore "online" oppure "offline"
all'output e ONLINE e OFFLINE sono due valori definiti con #define.
int check_tcp(int port, char *target){
 struct sockaddr_in client;
 struct hostent *hostinfo;
 int sock;
 if ((sock=socket(AF_INET, SOCK_STREAM, 0))==-1){
  printf("Error when trying to load the socket.\n");
 }else {
  client.sin_family=AF_INET;
  if ((hostinfo=gethostbyname(target))==NULL) send_img(OFFLINE);
  client.sin_addr=*((struct in_addr *) hostinfo->h_addr);
  client.sin_port=htons(port);
  try_connect_tcp(&sock,&client,1);
 }
 close (sock);
 return 1;
}
int try_connect_tcp(int *fd, struct sockaddr_in *sock, int timeout_secs){
 struct timeval timeout;
 fd_set write_fds;
 *fd = socket (PF_INET, SOCK_STREAM, 0);
 fcntl (*fd, F_SETFL, O_NONBLOCK);
 timeout.tv_sec = timeout_secs;
 timeout.tv_usec = 0;
 while (1) {
  if (connect (*fd, (struct sockaddr *) sock,sizeof (struct sockaddr_in)) < 0)
{
   if (errno != EAGAIN && errno != EINPROGRESS) {
    send_img(OFFLINE);
   }
  }else{
   send_img(ONLINE);
  }
  FD_ZERO (&write_fds);
  FD_SET (*fd, &write_fds);
  while (select (getdtablesize (), NULL, &write_fds, NULL, &timeout) < 0) {
   if (errno != EINTR) {
    perror ("select");
   }
  }
  if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
   send_img(OFFLINE);
  }
 }
 return 0;
