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.