Questo codice propone un Server che predispone due socket (porta 35000, porta 35001) sulle quali offre rispettivamente il messaggio di risposta <ciao> ed il messaggio di risposta <bye bye>. Queste due socket vengono assegnate alla maschera della select dopo che il server è stato predisposto per ricevere il segnale SIGUSR1(#16) agganciandolo ad un handler che non fa altro che visualizzare un messaggio che notifichi la ricezione del segnale.
/*
server
*/
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/file.h> #include <netdb.h> #include <fcntl.h> #include <stdio.h> #include <signal.h> #include <errno.h> #include <string.h>
#define PORTA_IT 35000 #define PORTA_USA 35001
extern int make_socket(struct sockaddr_in*,int*,ushort,char,FILE*); extern int connections(struct sockaddr_in*,int*,char*,ushort,char,FILE*); extern void clear_screen(void);
extern int errno; void segnale(); void reply_it(void); void reply_usa(void);
struct hostent *hp;
struct sockaddr_in claddr_it, /* socket d' ascolto per i clients I */
claddr_usa; /* socket d' ascolto per i clients USA */
int sock_it,sock_usa,lenght,len=sizeof(struct sockaddr_in);
char buf[10],*host;
main()
{
fd_set read_mask,temp_mask;
sigset(SIGUSR1,segnale);
/*assegna la struttura d'indirizzo per: - la sock_DG per le richieste di servizio da parte dei CLIENTS I. - la sock_DG per le richieste di servizio da parte dei CLIENTS USA.*/
if(make_socket(&claddr_it,&sock_it,PORTA_IT,'D',stderr))
{fprintf(stderr,"fallita la creazione della socket dei clients italiani\n");
exit();}
if(make_socket(&claddr_usa,&sock_usa,PORTA_USA,'D',stderr))
{fprintf(stderr,"fallita la creazione della socket dei clients amerrecani\n");
exit;}
FD_ZERO(&read_mask);
FD_SET(sock_it,&read_mask);
FD_SET(sock_usa,&read_mask);
temp_mask=read_mask;
printf("\n\nSono il processo %d.
Inviami un SIGUSR1 ogni tanto per vedere come si comporta la SELECT
quando il processo che la esegue riceve un segale.\n",getpid());
for(;;)
{
printf("\n\tSono sospeso sulla SELECT\n");
select(sock_usa+1,&read_mask,NULL,NULL,NULL);
if(FD_ISSET(sock_usa,&read_mask)) reply_usa();
if(FD_ISSET(sock_it,&read_mask)) reply_it();
read_mask=temp_mask;
}
}
void reply_it()
{
struct sockaddr_in peeraddr;
printf("\n\nRicevuta una richiesta da un client I!\n");
if(recvfrom(sock_it,buf,sizeof(buf),0,(struct sockaddr *)&peeraddr,&len)<0)
{fprintf(stderr,"fallita la ricezione del client I\n");return;}
lenght=ntohl(peeraddr.sin_addr.s_addr); hp=gethostbyaddr((char*)&lenght,sizeof(struct in_addr),peeraddr.sin_family); if(hp==NULL) host=(char *)inet_ntoa(peeraddr.sin_addr); else host=hp->h_name; fprintf(stderr,"Richiesta di connessione dal nodo %s ;porta %u \n\n", host,ntohs(peeraddr.sin_port));
sprintf(buf,"ciao");
if(sendto(sock_it,buf,sizeof(buf),0,(struct sockaddr *)&peeraddr,len)<0)
{fprintf(stderr,"fallito l'invio del b_cast alla ricerca di un NS\n");
return;}
}
void reply_usa()
{
struct sockaddr_in peeraddr;
printf("\nRicevuto una richiesta da un client USA!\n");
if(recvfrom(sock_usa,buf,sizeof(buf),0,(struct sockaddr *)&peeraddr,&len)<0)
{fprintf(stderr,"fallita la ricezione del client USA\n");return;}
lenght=ntohl(peeraddr.sin_addr.s_addr); hp=gethostbyaddr((char*)&lenght,sizeof(struct in_addr),peeraddr.sin_family); if(hp==NULL) host=(char *)inet_ntoa(peeraddr.sin_addr); else host=hp->h_name; fprintf(stderr,"Richiesta di connessione dal nodo %s ;porta %u \n\n", host,ntohs(peeraddr.sin_port));
sprintf(buf,"bye bye");
if(sendto(sock_usa,buf,sizeof(buf),0,(struct sockaddr *)&peeraddr,len)<0)
{fprintf(stderr,"fallito l'invio del b_cast alla ricerca di un NS\n");
exit();}
}
void segnale()
{
printf("Ricevuto il segnale utente\n");
}
/*
client italiano
*/
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <fcntl.h> #include <string.h> #include <signal.h> #include <errno.h>
#define PORTA_IT 35000
extern int make_socket(struct sockaddr_in*,int*,ushort,char,FILE*); extern int connections(struct sockaddr_in*,int*,char*,ushort,char,FILE*); extern void clear_screen(void); extern int errno;
main(argc,argv)
int argc;
char* argv[];
{
int sock,len=sizeof(struct sockaddr_in);
char buf[10],answer;
struct sockaddr_in nsaddr;
if(connection(&nsaddr,&sock,argv[1],PORTA_IT,'D',stderr))
{fprintf(stderr,"errore nella creazione della connessione\n");exit(0);}
do
{
if(sendto(sock,buf,sizeof(buf),0,(struct sockaddr *)&nsaddr,len)<0)
{fprintf(stderr,"fallito l'invio dela richiesta\n");
exit(0);}
if(recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr *)&nsaddr,&len)<0)
{fprintf(stderr,"fallita la ricezione del messaggio\n");
exit(0);}
printf("\nIl msg ricevuto e' %s\n",buf);
printf("Vuoi continuare s/n ?");answer=getchar();getchar();
}
while((answer=='s')||(answer=='S'));
}
/*
client americano
*/
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <fcntl.h> #include <string.h> #include <signal.h> #include <errno.h>
#define PORTA_USA 35001
extern int make_socket(struct sockaddr_in*,int*,ushort,char,FILE*); extern int connections(struct sockaddr_in*,int*,char*,ushort,char,FILE*); extern void clear_screen(void); extern int errno;
main(argc,argv)
int argc;
char* argv[];
{
int sock,len=sizeof(struct sockaddr_in);
char buf[10],answer;
struct sockaddr_in nsaddr;
if(connection(&nsaddr,&sock,argv[1],PORTA_USA,'D',stderr))
{fprintf(stderr,"errore nella creazione della connessione\n");exit(0);}
do
{
if(sendto(sock,buf,sizeof(buf),0,(struct sockaddr *)&nsaddr,len)<0)
{fprintf(stderr,"fallito l'invio dela richiesta\n");
exit(0);}
if(recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr *)&nsaddr,&len)<0)
{fprintf(stderr,"fallita la ricezione del messaggio\n");
exit(0);}
printf("\nIl msg ricevuto e' %s\n",buf);
printf("Vuoi continuare s/n ?");answer=getchar();getchar();
}
while((answer=='s')||(answer=='S'));
}
La ricezione del segnale provoca sul server un duplice effetto:
- l' interruzione dell' esecuzione del codice per eseguire l' handler associato al segnale (e fin qui niente di nuovo...)
- il settaggio di tutti i bit della maschera della select associati alle corrispondenti sockets !?!
Conseguentemente, in questo codice dopo la gestione del segnale, il server passa ad eseguire la funzione reply_usa() sospendendosi indefinitamente in attesa di un messaggio sulla socket sock_usa. A questo punto il codice funziona correttamente solamente nel caso in cui ,successivamente al segnale, pervengono al server due richieste la PRIMA da un client americano e la SECONDA da un client italiano. Se arriva PRIMA una richiesta da un client italiano il server non può gestirla finchè non sopraggiunge una richiesta usa; non solo ma se dopo la prima richiesta usa, che viene correttamente gestita, arriva un' altra richiesta usa, il server non può gestirla finchè non è sopraggiunta una richiesta italiana.
Questo comportamento è indipendente dal tipo di socket utilizzate (D_GRAM nell' esempio) in quanto il segnale va a modificare lo stato della maschera indipendentemente da ciò che è stato assegnato alla maschera.