Newsgroup: it.comp.programmare.win32
Titolo: select() e i socket udp

Devo scrivere una applicazione che utilizza i socket sotto 
Windows 2000 SP4. Uso Visual C++ (Visual Studio 6.0).
Ho scritto un semplice programma di test che riporto a fine messaggio
che  piu' o meno  implementa il seguente algoritmo:
- apri un socket UDP
- spedisci dati ad un ricevitore remoto usando sendto()
- chiama select per implementare una attesa (bloccante) della risposta
  fino a quando non sia scaduto un timeout.
- se il timeout non scade => chiama ioctlsocket per vedere
  di quanti byte e' fatta la risposta.
- chiama recvfrom per leggere i dati dal socket
  (leggi il numero di byte restituito da ioctl).
Ottengo uno strano comportamento:
Se il ricevitore remoto e' pronto a ricevere e fornire una
risposta, tutto funziona
Se l'IP del ricevitore non esiste tutto sembra ancora funzionare
(ovvero select esce con 0 => codice di timeout, dopo un tempo
di attesa pari al timeout impostato)
Se l'IP del ricevitore esiste ma nessun software che riceve
e' in esecuzione => la select ritorna come se ci fosse
qualcosa da leggere sul socket e ioctlsocket indica che 
effettivamente c'e' 1 byte da leggere. Ho verificato con
Ethereal che effettivamente l'unico pacchetto che passa sulla
ethernet e' quello che e' spedito dal mio programma al
ricevitore remoto e non c'e' alcuna risposta.
Comunque in questo caso, quando chiamo recvfrom (per leggere 1 byte)
ottengo che recvfrom restituisce SOCKET_ERROR e WSAGetLastError
retituisce 10054 (WSAECONNRESET).
Mi sarei aspettato un timeout sulla select sia nel caso in cui
l'IP remoto non esiste che nel caso in cui l'IP esiste
ma non c'e' alcuna applicazione in grado di rispondere
(linux e Sun Solaris si comportano cosi' per quanto ne so).
Vorrei capire come si puo' impostare un timeout (bloccante) su
un socket UDP che funzioni sia quando non esiste
l'IP remoto che quando l'applicazione remota e' giu'.
Se possibile vorrei usare socket B
Grazie in anticipo,
Marco
#include <windows.h>
void f()
{
  char logb[256];
  memset(logb,0,sizeof(logb));
  WORD wVersionRequested;
  WSADATA wsaData;
  int err;
 
  wVersionRequested = MAKEWORD( 2, 2 );
 
  err = WSAStartup( wVersionRequested, &wsaData );
  if ( err != 0 ) {
    return ;
  }
  int sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
 
  struct linger ling;
  ling.l_linger=0;
  ling.l_linger=1;
  setsockopt(sock,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling));
 
  struct sockaddr_in sin,sinloc;
  memset(&sin,0,sizeof(sin));
  int sinlen=sizeof(sin);
  sin.sin_family=AF_INET;
  sin.sin_port=htons(12345);
  sin.sin_addr.s_addr=inet_addr("141.137.142.100");
  SetLastError(0);
 
  memset(&sinloc,0,sizeof(sinloc));
  sinloc.sin_addr.s_addr=inet_addr("141.137.142.233");
  sinloc.sin_port=htons(12345);
  sinloc.sin_family=AF_INET;
  int ret=0;
  ret=bind(sock,(struct sockaddr *)&sinloc,sizeof(sinloc));
  ret=sendto(sock,"pippo",5,0,(struct sockaddr *)&sin,sinlen);
  int t=GetLastError();
 
  if(ret != 5)
  {
    memset(logb,0,sizeof(logb));
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,WSAGetLastError(),0,logb,sizeof(logb)-1,0);
  }
  char buf[500000];
  memset(buf,0,sizeof(buf));
  fd_set readfs;
  FD_ZERO(&readfs);
  FD_SET(sock,&readfs);
  timeval tv;
  tv.tv_sec=15;
  tv.tv_usec=0;
  ret=select(sock+1,&readfs,0,0,&tv);
  t=GetLastError();
 
  if((ret !=0) && (ret != SOCKET_ERROR))
  {
    unsigned long how_many;
 
    ret=ioctlsocket(sock,FIONREAD,&how_many);
    t=GetLastError();
 
    if(ret==0)
    {
      ret=recvfrom(sock,&buf[0],how_many,0,(struct sockaddr *)
&sin,&sinlen);
      t=GetLastError();
 
      if(ret==how_many)
      {
        MessageBox(0,buf,"ricevuto!",MB_OK);
      }
      else
      {
        memset(logb,0,sizeof(logb));
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,WSAGetLastError(),0,logb,sizeof(logb)-1,0);
      }
    }
    else
    {
      memset(logb,0,sizeof(logb));
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,WSAGetLastError(),0,logb,sizeof(logb)-1,0);
    }
  }
  else
  {
    memset(logb,0,sizeof(logb));
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,WSAGetLastError(),0,logb,sizeof(logb)-1,0);
  }
}
int main()
{
  f();
  return 0;
}
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

Ciao,
allora, io č un po' che non lavoro con i socket, ma per fare una
select() bloccante con timeout si dovrebbe impostarlo (nell'esempio il
socket č sd) con un codice del tipo:
  fd_set sk;
  struct timeval tm;   // timeout massimo del select
  int sv;
  tm.tv_sec  = r;
  tm.tv_usec = 0;
  FD_ZERO(&sk);             // ripulisce la struttura dati
  FD_SET(sd,&sk);           // definisco il socket da analizzare
  // select e' usata in lettura quindi i parametri relativi all'attesa
  // di poter scrivere o di un eccezione dati out-of-band sono posti
  // a NULL
  sv=select(sd+1,&sk,NULL,NULL,&tm);
  if (sv<0)  // c'e' stato un errore sul descrittore
    error("Errore nella select()");
 
per quanto riguarda il problema di "avere una risposta", penso che non
sia il caso del protocollo UDP che a differenza del TCP non prevede
pacchetti di ritorno.
Di puů cosě su 2 piedi non so dirti, sperando di non aver sparato
cavolate.
M

 Windows 2000 SP4. Uso Visual C++ (Visual Studio 6.0).
<snippone>
Vedi se questo ti č di aiuto
http://support.microsoft.com/kb/263823
Ciao
-- 
* ObiWan
Microsoft MVP: Windows Server - Networking
http://www.microsoft.com/communities/MVP/MVP.mspx
http://mvp.support.microsoft.com
DNS "fail-safe" for Windows clients.
http://www.ntcanuck.com
Newsgroups and forums
news://
news.ntcanuck.com
http://forums.ntcanuck.com
408+ XP/2000 tweaks and tips
http://www.ntcanuck.com/tq/Tip_Quarry.htm