1.        SOA/esempi utili catalogati/c_ps/2006-06-21.c

 
/*TESTO 2006-06-21
 
Si realizzi in ambiente Unix/C il SERVER della seguente interazione tra processi:
 
- il sistema consiste di due processi: un processo server Ps e un processo cliente Pc; per la comunicazione tra Ps e i processi
cilenti Pcivengono utilizzate socket Stream; scegliere la porta su cui il sevrer offre il servizio: 789 o 7890 (motivare). Il
server crea un figlio e poi si pone in attesa dell'arrivo di dati dal client;
- il client invia una stringa testuale;
- il processo server la legge, la invia al figlio, che a sua volta la visualizza a video;
- se la stringa e' STOP il processo server fa terminate il processo figlio mediante l'invio di un segnale, e poi termina anch'esso;
altrimenti il server si rimette in attesa di dati dal client.
 
Come generico client Ps si suggerisce l'utilizzo del programma telnet, invocato come "telnet localhost numeroportaserver" 
(es. "telnet localhost 7890"). Attenzione che telnet attacca ad ogni stringa inviata la sequenza di caratteri "\r\n". 
 
Si siggerisce l'utilizzo delle funzionie C strcmp per verificare la presenza della parola chiave STOP.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 7890
 
//Funzione di gestione segnali.
void handler()
{
  printf("\nProcesso %d esce",getpid());
 
  exit(0);
}
 
int main()
{
  char buffer[256]="";
  int pidFiglio;
 
  int p[2]; //la pipe
 
  struct sigaction sig;
  struct sockaddr_in server,client;
  int sock,msgsock;
  int lenght;
  if(pipe(p)<0) //creo la pipe, sara' il canale di comunicazione tra padre e figlio
    {
      perror("pipe");
      exit(-1);
    }
 
  if((pidFiglio=fork())<0)  //creo il figlio che stampera' le stringhe
    {
      perror("fork figlio");
      exit(-1);
    }
  else
    if(pidFiglio==0) //sono il figlio?
      { 
         //FIGLIO
         printf("Sono il figlio con pid %d\n",getpid());
 
         close(p[1]); //chiudo il descrittore di scrittura della pipe, non mi serve
 
         //installo il gestore affidabile del segnale di uscita per tutti i processi
         //non e' strettamente necessario, il testo non lo chiedeva ed era sufficiente (e necessaria) una gestione non affidabile
         //lo metto giusto come ulteriore esempio (minimo) di gestione affidabile dei segnali
         sig.sa_handler = handler; 
         sigemptyset(&sig.sa_mask);
         sig.sa_flags=SA_RESTART;
 
         sigaction(SIGINT,&sig,NULL);
 
         do //ciclo infinito di lettura dalla pipe
           {
             if(read(p[0],buffer,sizeof(buffer))<0) //leggo la stringa che mi invia il sevrer
               perror("read pipe");
 
             printf("\nFiglio: ho ricevuto la stringa %s",buffer);
           }
         while(1);
      }
    else //altrimenti sono il padre (server)
      {
         //PADRE
         printf("Sono il padre con pid %d\n",getpid());
 
         sock=socket(AF_INET,SOCK_STREAM,0); //creo la socket
         if(sock<0)
           {
             perror("creazione stream socket");
             kill(pidFiglio,SIGKILL);
             exit(-1);
           }
 
         //preparo la struttura sockaddr_in per settare i parametri della socket
         server.sin_family=AF_INET;         //internet protocol
         server.sin_addr.s_addr=INADDR_ANY; //ascolto da tutte le interfacce
         server.sin_port=htons(PORT);       //e dalla porta specificata
         if(bind(sock,(struct sockaddr *)&server,sizeof(server))<0)
           {
             perror("binding stream socket");
             kill(pidFiglio,SIGINT);
             exit(-1);
           }
 
         lenght=sizeof(server);
         if(getsockname(sock,(struct sockaddr *)&server,(socklen_t *)&lenght)<0)//leggo il nome della socket
           {
             perror("getting socket name");
             kill(pidFiglio,SIGINT);
             exit(-1);
           }
 
         printf("Socket port # %d\n",ntohs(server.sin_port));
 
         listen(sock,5); //massimo di 5 connesioni in attesa
 
         msgsock=accept(sock,(struct sockaddr *)&client,(socklen_t *)&lenght);//attendo connesioni...
         if(msgsock == -1)
           {
             perror("accept");
             exit(-1);
           }
 
         do //questo e' il ciclo principale del server: legge i messaggi che gli manda il client e li gira al figlio
           {          
             if(read(msgsock,buffer,sizeof(buffer))<0) //leggo il messaggio
               perror("reading message");
 
             if(!strncmp(buffer,"STOP\r\n",6))//se ricevo STOP uccido il figlio ed esco
               {
                 kill(pidFiglio,SIGINT); //uccido il figlio
                 close(sock);
                 close(msgsock);
                 exit(0);
               }        
 
             //mando la stringha ricevuta al figlio
             if(write(p[1],buffer,sizeof(buffer))<0)
               perror("writing message");
           }
         while(1);
      }
 
  
  return 0;
}

 

 

2 SOA/esempi utili catalogati/c_ps/2006-06-21-ver2.c/* TESTO 2006-06-21-ver2
 
Si realizzi in ambiente Unix/C il server della seguente interazione tra processi :
 
-il sistema consiste di due tipi di processi: un processo server Ps e i processi clienti Pci;
-per la comunicazione tra Ps e i processi clienti Pci vengono utilizzate socket Stream;
-il server Ps offre un servizio concorrente (un figlio per ogni connessione) alla porta 987
oppure 9876 (motivare la scelta della porta utilizzata);
-il client invia una stringa del tipo cmd1 | cmd2 (digitata dall'utente) affinch`e un
opportuna coppia di processi sul server realizzi il piping dei comandi cmd1 e cmd2 ;
-lo standard output del processo che realizza cmd2 deve essere ridiretto sulla socket
connessa affinch`e sia ricevuto e visualizzato dal cliente ;
-a partire dal momento in cui riceve un segnale SIGUSR1, il server Ps deve memorizzare
in un file di testo (denominato server-log.txt) gli indirizzi IP dei clienti che richiedono
il servizio.
 
Come generico client Pci, si suggerisce l'utilizzo del programma telnet, invocato come
telnet localhost numeroportaserver. Una volta connessi al server, scrivere ad esempio
ls | wc nel terminale del telnet per verificare il funzionamento del server.
 
Deve essere utilizzata la gestione affidabile dei segnali.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <arpa/inet.h>
 
 
//le porte sotto il 1024 sono riservate
#define PORT 9876
 
//descrittore del file server-log.txt
int f=0;
 
 
//Funzione di gestione segnali.
void handler()
{
  //FILE /////////////////////////
  //
  if(!f)
    if((f=open("server-log.txt",O_CREAT|O_WRONLY|O_TRUNC))<0)
      perror("open file");
  ///////////////////////////////
}
 
int main()
{
  char * env[]={NULL,(char *)0};
  char buffer[256]="",app[256]="";
  char * buffer2;
  char * nome_cli;
  struct sigaction sig;
  struct sockaddr_in server,client;
  int sock,msgsock;
  int lenght;
  int pid,p[2];
 
  printf("Sono il server con pid %d\n",getpid());
 
  //SOCKET //////////////////////
  //
  //preparo la struttura sockaddr_in per settare i parametri della socket
  sock=socket(AF_INET,SOCK_STREAM,0); //creo la socket
  if(sock<0)
    {
      perror("creazione stream socket");
      exit(-1);
    }
 
  //preparo la struttura sockaddr_in per settare i parametri della socket
  server.sin_family=AF_INET;         //internet protocol
  server.sin_addr.s_addr=INADDR_ANY; //ascolto da tutte le interfacce
  server.sin_port=htons(PORT);       //e dalla porta specificata
  if(bind(sock,(struct sockaddr *)&server,sizeof(server))<0)
    {
      perror("binding stream socket");
      exit(-1);
    }
 
  //leggo la porta che mi e' stata effettivamente assegnata
  lenght=sizeof(server);
  if(getsockname(sock,(struct sockaddr *)&server,(socklen_t *)&lenght)<0)//leggo il nome della socket
    {
      perror("getting socket name");
      exit(-1);
    }
 
  printf("Socket port # %d\n",ntohs(server.sin_port));
 
  listen(sock,5); //massimo di 5 connesioni in attesa
  ////////////////////////////////
 
 
  //SEGNALI //////////////////////
  //
  sig.sa_handler = handler; //gestore del segnale
  sigemptyset(&sig.sa_mask);
  sig.sa_flags=SA_RESTART;
 
  sigaction(SIGUSR1,&sig,NULL);
  ////////////////////////////////
 
  //ciclo infinito del server in attesa di connessioni
  do
    {
 
      msgsock=accept(sock,(struct sockaddr *)&client,(socklen_t *)&lenght);//attendo connesioni...
      if(msgsock == -1)
         {
           perror("accept");
           exit(-1);
         }
 
      //se e' stato ricevuto un segnale il descrittore f e' diverso da zero
      if(f)
         {
           //leggo il nome del client
           nome_cli=inet_ntoa(client.sin_addr);
 
           //lo scrivo bel file
           write(f,nome_cli,strlen(nome_cli));
 
           fflush(NULL);
         }
 
      if((pid=fork())<0)  //creo il figlio che gestira' la connessione
         {
           perror("fork figlio gestore connessione");
           exit(-1);
         }
      if(pid==0) //sono il figlio?
         {
           /////////////////////////////
           //CODICE FIGLIO GESTORE
 
           printf("Sono il gestore della connessione con pid %d\n",getpid());
 
           //ciclo del gestore della connessione: continua a leggere le stringhe del client e ad eseguire i comandi richiesti
           do
             {
               //resetto i buffer
               memset(app,0,sizeof(app));
               memset(buffer,0,sizeof(buffer));
 
               //leggo la stringa che mi manda il client con i comandi da eseguire
               if(read(msgsock,app,sizeof(app))<0)
                 {
                   perror("reading message");
                   exit(-1);
                 }
 
               //tolgo gli spazi e i caratteri aggiunti da telnet... sicuramente c'era un modo migliore!!
               int i=0,j=0;
               do
                 {
                   if(app[i]!=' ' && app[i]!='\r' && app[i]!='\n')
                     buffer[j++]=app[i];
                 }
               while(++i<strlen(app));
 
               printf("Eseguo il comando %s\n",buffer);
 
               //se c'e' il carettere | allora creo un altro figlio che eseguira' il secondo comando
               //metto in buffer2 la posizione del simbolo | piu' uno, che rappresenta la posizione del secondo comando
               if((buffer2=strchr(buffer,'|')+1))
                 {
                   //pipe di comunicazione tra i processi
                   if(pipe(p))
                     perror("pipe");
 
                   if((pid=fork())<0)  //creo il nipote che eseguira' il secondo comando
                     {
                       perror("fork figlio secondo comando");
                       exit(-1);
                     }
                   if(pid==0) //sono il nipote?
                     {
                       /////////////////////////////////
                       //CODICE NIPOTE ESECUTORE di cmd2
 
                       //tronco la stringa buffer al carattere |
                       //in questo modo mi resta solo il primo comando
                       buffer[buffer2-buffer-1]=0x0;
 
                       //chiudo stdount
                       close(1);
 
                       //il nuovo stdout e' lo stdin del figlio cmd2
                       if(dup(p[1])<0)
                          perror("dup1");
 
                       close(p[0]);
                       close(p[1]);
 
                       env[0]=buffer;
                       if(execvp(buffer,env)<0)
                          perror("execv primo");
 
                       exit(0);
                       ////////////////////////////
                     }
 
                   if((pid=fork())<0)  //creo il nipote che eseguira' il primo comando
                     {
                       perror("fork figlio primo comando");
                       exit(-1);
                     }
                   if(pid==0) //sono il nipote?
                     {
                       /////////////////////////////////
                       //CODICE NIPOTE ESECUTORE di cmd1
                       //chiudo stdin e stdout
                       close(0);
                       close(1);
 
                       //nuovo stdin
                       if(dup(p[0])<0)
                          perror("dup2");
 
                       //nuovo stdout
                       if(dup(msgsock)<0)
                          perror("dup3");
 
                       close(p[0]);
                       close(p[1]);
 
                       env[0]=buffer2;
                       if(execvp(buffer2,env)<0)
                          perror("execv secondo");
 
                       exit(0);
                       ////////////////////////////////
                     }
                 }
               else
                 {
                   printf("La stringa deve essere nel formato cmd1 | cmd2\n");
                   exit(0);
                 }
 
               close(p[0]);
               close(p[1]);
             }
           while(1);
         }
      close(msgsock);
    }
  while(1);
 
 
  return 0;
}

 

2.         

3-SOA/esempi utili catalogati/c_ps/2006-07-19.c/*TESTO 2006-07-19
 
Si realizzi in ambiente Unix/C il SERVER della seguente interazione tra processi:
 
- il sistema consiste di 3 tipi di processi: server Ps, un processo Pstore e i clienti Pci;
- per la comunicazione tra Ps e i processi clienti Pci vengono utilizzate socket Stream;
- il server Ps offre un servizio concorrente (un figlio per ogni connesione) alla porta 876 oppure alla porta 8765 (giustificare)
- inizialmente il server Ps attiva un processo figlio persistente Pstore che visualizza il proprio PID e gestisce un vettore
  si 10 elementi interi aggiornato sulla base delle richieste dei clienti
- i client inviano stringhe del tipo
 
  "STORE indirizzo valore_intero" con 0<=indirizzo<=9. Ad esempio "STORE 0 11". La richiesta sovrascrive il valore
  eventualmente gia' memorizzato all'indirizzo specificato.
 
- alla ricezione del segnale SIGUSR1 il processo Pstore deve visualizzare il contento del vettore;
- alla ricezione del segnale SIGUSR2 il processo Pstore deve azzerare tutti gli elementi del vettore;
 
Deve essere usata la gestione affidabile dei segnali.
 
Come generico client Ps si suggerisce l'utilizzo del programma telnet, invocato come "telnet localhost numeroportaserver" 
(es. "telnet localhost 8765"). Una volta connessi al sevrer scrivere, ad esempio, STORE 8 22 [INVIO] nel terminale del telnet
e inviare un SIGUSR1 al processo Pstore per verficare il funzionamento del server.
 
Si siggerisce l'utilizzo delle funzioni C sscanf per estrarre dal messaggio l'indirizzo del messaggio e il valore da assegnare, e strcmp per 
verificare la presenza della parola chiave STORE
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
 
 
#define PORT 8765
 
int storeVet[10];
int sock,msgsock;
 
 
 
//Funzione di gestione segnali. Se ne potevano fare anche 3 diverse
void handler(int signo)
{
  static int i=0;
 
  switch(signo) //che segnale ho riceuvuto?
    {
    case SIGUSR1:
      {
         printf("\nStampo i valori del vettore: ");
 
         for(i=0;i<10;i++)
           printf("%d ",storeVet[i]);
 
         printf("\n");
         break;
      }
    case SIGUSR2:
      {
         printf("\nAzzero i valori del vettore\n");
         memset(storeVet,0,sizeof(storeVet));
         break;
      }
    case SIGINT:
      {
         printf("\nProcesso %d esce\n",getpid());
 
         close(sock);
         close(msgsock);
         exit(0);
      }
    }
 
}
 
 
 
 
 
int main()
{
  struct //ho pensato di usare una struttura per leggere la posizione e il numero da inserire
  {
    int pos;
    int num;
  }storeRec;
 
  char buffer[256]="";
  char comando[256]="";
  int pidStore;
 
  int p[2]; //la pipe
 
  struct sigaction sig,sig1,sig2;
 
  struct sockaddr_in server,client;
  int lenght,rval;
 
 
  if(pipe(p)<0) //creo la pipe, sara' comune per tutti i processi
    {
      perror("pipe");
      exit(-1);
    }
 
 
  sig2.sa_handler = handler; //installo il gestore del segnale di uscita per tutti i processi. Non obbligatorio
  sigemptyset(&sig2.sa_mask);
  sig2.sa_flags=SA_RESTART;
 
  sigaction(SIGINT,&sig2,NULL);
 
 
  if((pidStore=fork())<0)  //creo il figlio Pstore, che sara' permenente fino alla fine del programma
    {
      perror("fork Pstore");
      exit(-1);
    }
  else
    if(pidStore==0) //sono il figlio(Pstore)?
      { 
         //PSTORE
         printf("Sono il Pstore con pid %d\n",getpid());
 
         close(p[1]);     //chiudo il descrittore discrittura della pipe, non mi serve
 
         sig.sa_handler = handler; //installo il gestore del segnale SIGUSR1
         sigemptyset(&sig.sa_mask);
         sigaddset(&sig.sa_mask,SIGUSR2); //blocco SIGUSER2 durante la gestione di SIGUSR1
         sig.sa_flags=SA_RESTART;
 
         sig1.sa_handler = handler; //installo il gestore del segnale SIGUSR2
         sigemptyset(&sig1.sa_mask);
         sigaddset(&sig1.sa_mask,SIGUSR1); //blocco SIGUSER2 durante la gestione di SIGUSR2
         sig1.sa_flags=SA_RESTART;
 
         sigaction(SIGUSR1,&sig,NULL);
         sigaction(SIGUSR2,&sig1,NULL);
 
         do //ciclo infinito di lettura dalla pipe
           {
             if(read(p[0],&storeRec,sizeof(storeRec))<0) //leggo il dato che contiene posizione e nuovo numero
               perror("read pipe");
 
             printf("Pstore: ricevuto %d %d\n",storeRec.pos,storeRec.num);
             storeVet[storeRec.pos]=storeRec.num; //setto in nuovo numero
           }
         while(1);
      }
    else //altrimenti sono il padre (server)
      {
         //PADRE
         printf("Sono il padre con pid %d\n",getpid());
 
         sock=socket(AF_INET,SOCK_STREAM,0); //creo la socket
         if(sock<0)
           {
             perror("creazione stream socket");
             kill(pidStore,SIGKILL);
             exit(-1);
           }
 
         //preparo la struttura sockaddr_in per settare i parametri della socket
         server.sin_family=AF_INET;         //internet protocol
         server.sin_addr.s_addr=INADDR_ANY; //ascolto da tutte le interfacce
         server.sin_port=htons(PORT);       //e dalla porta specificata
         if(bind(sock,(struct sockaddr *)&server,sizeof(server))<0)
           {
             perror("binding stream socket");
             kill(pidStore,SIGINT);
             exit(-1);
           }
         lenght=sizeof(server);
         if(getsockname(sock,(struct sockaddr *)&server,(socklen_t *)&lenght)<0)//leggo il nome della socket
           {
             perror("getting socket name");
             kill(pidStore,SIGINT);
             exit(-1);
           }
 
         printf("Socket port # %d\n",ntohs(server.sin_port));
 
         listen(sock,5); //massimo di 5 connesioni in attesa
 
         do //questo e' il ciclo principale del server: attende connesioni, e crea un figlio per ogni una
           {
             msgsock=accept(sock,(struct sockaddr *)&client,(socklen_t *)&lenght);//attendo connesioni...
 
             if(msgsock == -1)
               {
                 perror("accept");
                 exit(-1);
               }
             
             if(fork()==0) //genero il figlio che gestira' la connesione attuale
               {
                 //FIGLIO GESTORE DELLA CONNESIONE
                 close(sock);
                 close(p[0]);
 
                 do 
                   {
                     if((rval=read(msgsock,buffer,256))<0) //leggo il messaggio
                       perror("reading message");
 
 
                     sscanf(buffer,"%s %d %d",comando,&(storeRec.pos),&(storeRec.num)); //estraggo comando, posizione nel vettore e nuovo valore
                     printf("Figlio socket: ricevuto %s %d %d\n",comando,storeRec.pos,storeRec.num);
 
                     if(!strncmp(comando,"STORE",5))//se il comando era effettivamente STORE, agisco di conseguenza
                        {
                          if(write(p[1],&storeRec,sizeof(storeRec))<0)
                            perror("write pipe");
                       }
                       
                   }
                 while(1);
               }
             else
               close(msgsock);
           }
         while(1);
      }
 
    return 0;
}

 

 

4-SOA/esempi utili catalogati/c_ps/2006-09-08.c/******************************************************************************************************************
 *
 * Questo esercizio poteva essere risolto in piu' modi, e con diverse interpretazioni al testo tutte piu' o meno
 * corrette. In questa particolare soluzione:
 *
 * -alla ricezione del SIGUSR1 si passa dalla porta 8001 alla 8080. Alla ricezione del SIGUSR2 si attiva
 *  anche la porta 8080 in aggiunta alla 8001. Dopo la ricezione di uno qualunque dei due segnali ENTRAMBI verranno
 *  ignorati;
 *
 * -i processi figli che ricevono il messaggio ed estraggono l'ultima parola non escono subito
 *  dopo la prima ricevione, ma restano sempre attivi fino a quando non vengono uccisi;
 *
 * -ho deciso di non aprire subito entrambe le socket, ma di aprirne una, chiuderla se necessario, aprirne una seconda 
 *  se necessario. Si poteva anche aprirne subito due e decidere quale usare con una var globale
 *
 *
 *  ATTENZIONE: per la gestione della doppia porta in contemporaneo la cosa piu' ortodossa e' usare la
 *  funzione select. Questa pero' non e' stata vista dagli studenti del corso di Broggi, quindi qui
 *  di seguito e' mostrata una soluzione alternativa che non ne fa uso.
 *
 ********************************************************************************************************************/
 
/*TESTO 2006-09-08
 
Si realizzi in ambienteUnix/C il SERVER della seguente interazione tra processi:
 
-il sistema consistye di due tipi di processi: un server Ps e i client Pci;
-per la comunicazione tra Ps e i processi Pci vengono utilizzate socket STREAM;
-il server Ps offre un servizion concorrente (un figlio per ogni connessione) alle potre 8001
 e/o 8080;
-il sevrer, che opera inizialmente sulla porta 8001, dopo aver ricevuto un segnale SIGUSR1 attende
 connessioni sulla porta 8080 (OPZIONALE: la ricezione di un segnale SIGUSR2 fa si che il sevrer attenda
 su entrambe le porta); N.B. dopo aver ricevuto un segnale SIGUSR1/2, ulteriori segnali SIGUSR1/2 devono
 essere ignorati;
-il clinet invia una stringa contenente parole separate da spazi, ed ottiene in risposta l'ultima parola
 inviata
 
Deve essere utilizzata la gestione affidabile dei segnali. Si noti che una accept interrota dalla ricezione di un 
sengale ritorna -1 con errno che vale EINTR.
 
Come generico clinet Pci si suggerisce di utilizzare i programma telnet invocato come "telnet localhost porta". Una
volta connessi scrivere, ad esempio, "pippi tololino pluto" per verificare il funzionamento del programma. Telnet invia
assieme alla stringa digitata i caratteri di fine linea \r\n.
 
Si rammenta la presenza della funzione char * strrchr(const char *s,int c). Essa ritorna un puntatore all'ultima occorenza
del carattere c nella stringa s.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
 
 
 
#define PORT1 8001
#define PORT2 8080
 
int sock,msgsock,porta;
struct sockaddr_in server;
 
 
//funzione per aprire la porta 8080
void apri8080()
{
  //ne creo una nuova
  sock=socket(AF_INET,SOCK_STREAM,0);
  if(sock<0)
    {
      perror("creazione stream server");
      exit(-1);
    }
 
  server.sin_port=htons(PORT2);       //imposto la nuova porta, gli altri campi vanno gia' bene
  if(bind(sock,(struct sockaddr *)&server,sizeof(server))<0)
    {
      perror("binding stream socket");
      exit(-1);
    }
 
  printf("Server %d on port # %d\n",getpid(),ntohs(server.sin_port));
  listen(sock,5); //listen sulla PORT2, massimo di 5 connesioni in attesa
}
 
 
//Funzione di gestione segnali
void handler(int signo)
{
  int ps;
  struct sigaction sig;
 
 
  //ignoro i successivi SIGUSR1 e SIGUSR2
  //sigprocmask non funziona dentro l'handler del segnale stesso
  //si poteva usare una var globale che controllasse se e' la prima volta che ricevo questo segnale
  sig.sa_handler = SIG_IGN; //per ignorare il segnale (vedi man sigaction)
  sigemptyset(&sig.sa_mask);
  sig.sa_flags=0;
  sigaction(SIGUSR1,&sig,NULL);
  sigaction(SIGUSR2,&sig,NULL);
 
  switch(signo) //che segnale ho riceuvuto?
    {
    case SIGUSR1:
      {
           //chiudo la vecchia socket
         close(sock);
 
         //apro una socket sulla porta 8080
         apri8080();
 
         break;
      }
    case SIGUSR2: //(opzionale)
      {
         //creo un nuovo figlio, che fungera' da SERVER sull'altra porta
         if((ps=fork())<0)
           {
             perror("fork nuovo server");
             exit(-1);
           }
         if(ps==0)//CODICE SERVER FIGLIO
           {
 
             //chiudo la vecchia socket che ho ereditato dal server padre
             close(sock);
 
             //apro una socket sulla porta 8080
             apri8080();
 
           }//FINE SERVER FIGLIO
 
         break;
      }
    case SIGINT: //non richiesto
      {
         printf("\nProcesso %d esce\n",getpid());
 
         close(sock);
         close(msgsock);
         exit(0);
      }
    }
 
}
 
 
 
 
int main()
{
  char buffer[256];
  char * ultimo;
 
  struct sigaction sig;
 
  struct sockaddr_in client;
  int lenght,pid;
 
 
  //creo la SOCKET
  sock=socket(AF_INET,SOCK_STREAM,0);
  if(sock<0)
    {
      perror("creazione stream socket");
      exit(-1);
    }
 
  //preparo la struttura sockaddr_in per settare i parametri della socket con PORT1
  server.sin_family=AF_INET;         //internet protocol
  server.sin_addr.s_addr=INADDR_ANY; //ascolto da tutte le interfacce
  server.sin_port=htons(PORT1);       //e dalla porta specificata
  if(bind(sock,(struct sockaddr *)&server,sizeof(server))<0)
    {
      perror("binding stream socket");
      exit(-1);
    }
 
  printf("Server %d on port # %d\n",getpid(),ntohs(server.sin_port));
 
  listen(sock,5); 
 
 
 
  //SEGNALI
  sig.sa_handler = handler; //installo il gestore del segnale SIGUSR1
  sigemptyset(&sig.sa_mask);
  sigaddset(&sig.sa_mask,SIGUSR2); //blocco SIGUSR2 durante la gestione di SIGUSR1
  sig.sa_flags=0;
  sigaction(SIGUSR1,&sig,NULL);
 
  sigemptyset(&sig.sa_mask);
  sigaddset(&sig.sa_mask,SIGUSR1); //blocco SIGUSR1 durante la gestione di SIGUSR2
  sigaction(SIGUSR2,&sig,NULL);
 
  sigemptyset(&sig.sa_mask);
  sigaction(SIGINT,&sig,NULL);
 
 
  //CICLO PRINCIPALE
  do //attende connesioni, e crea un figlio per ogni una
    {
      lenght=sizeof(client);
      msgsock=accept(sock,(struct sockaddr *)&client,(socklen_t *)&lenght); //attendo connesioni...
 
      if(msgsock == -1 && errno!=EINTR) //controllo se c'e' un errore e se questo e' dovuto ad un segnale, nel qual caso lo ignoro
         {
           perror("accept"); //se invece l'errore non dipende da un segnale c'e' qualcosa che non va ed esco
           exit(-1);
         }
      if(errno!=EINTR) //se sono uscito dalla accept per un segnale allora non devo generare nessun figlio gestore...
         {
           if((pid=fork())<0) //genero il figlio che gestira' la connesione attuale
             {
               perror("fork gestore");
               exit(-1);
             }
           else
             if(pid==0)
               {
                 //CODICE FIGLIO GESTORE DELLA CONNESIONE
                 close(sock);
 
                 printf("Figlio gestore della connesione su porta %d, utilzza porta %d per comunicazione, pid %d\n",ntohs(server.sin_port),ntohs(client.sin_port),getpid());
 
                 do 
                   {
                     memset(buffer,0,256);//azzero il buffer di lettura
 
                     if(read(msgsock,buffer,256)<0) //leggo il messaggio
                       perror("reading message");
                     else
                       {
                          printf("Figlio %d ha ricevuto %s\n",getpid(),buffer);
 
                          //estraggo il puntatore all'ultimo spazio
                          ultimo=strrchr(buffer,' ');
 
                          if(ultimo)
                            ultimo++;      //in questo modo punto al primo carattere dopo lo spazio
                          else
                            ultimo=buffer; //se buffer non contiene spazi, allora e' costituito da una sola parola, e rimando tutto buffer
 
                          if(write(msgsock,ultimo,strlen(ultimo))<0) //speidsco l'ultima parola
                            perror("writing message");
                       }
 
                   }
                 while(1);
                 //FINE CODICE FIGLIO GESTORE
               }
         }
      //CODICE PADRE
      close(msgsock);
    }
  while(1);
 
 
  
  return 0;
}

 

 

5-SOA/esempi utili catalogati/c_ps/2006-09-25.c/*TESTO  2006-09-25
 
Si realizzi in ambienteUnix/C la seguente interazione tra processi:
 
-il processo genera due processi figli;
-ogni processo figliovisualizza il proprio pid e un numero casuale tra 0 e N compresi; N e' un numero intero che l'utente 
 specifica come unico argomento di invocazione del programma;
-il processo che ha generato il numero casuale minore invia un SIGUSR1 all'altro processo figlio, visualizza un messaggio
 con il proprio pid e si pone in attesa di un segnale;
-il processo che riceve il segnale SIGUSR1 visualizza un messaggio con il proprio pid e si termina;
-il padre, dopo che un figlio e' terminato, invia un segnale all'altro figlio, e termina con un messaggio.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
 
 
 
 
//Funzione di gestione segnali
void handler()
{
  printf("Processo figlio %d ha ricevuto un SIGUSR1 ed esce\n",getpid());
 
  exit(3);
}
 
 
 
 
int main(int argc, char *argv[])
{
  struct sigaction sig;
  sigset_t newmask;
  int exit_pid,pid[2],status,pp[2][2],numero,mynumero,N,i;
 
 
  if(argc<2 || atoi(argv[1])<=0 || atoi(argv[1])>=RAND_MAX)
    {
      printf("ERRORE negli argomenti\n");
      printf("Uso: programma <N>\n");
      printf("N deve essere maggiore di 0 e minore di RAND_MAX\n");
      exit(-1);
    }
 
  //setto N
  N=atoi(argv[1]);
 
  //creo le due pipe che i figli useranno per scambiarsi i pid e il numero casuale
  //una pp[0] verra usata in scrittura dal primo figlio, pp[2] dal secondo
  //
  //pp e' un vettore di pipe
  if(pipe(pp[0])<0) 
    {
      perror("pipe 0");
      exit(-1);
    }
 
  if(pipe(pp[1])<0) 
    {
      perror("pipe 1");
      exit(-1);
    }
 
  //GENERO I FIGLI
  for(i=0;i<2;i++)
    {
      if((pid[i]=fork())<0) //genero il primo figlio
         {
           perror("fork primo figlio");
           exit(-1);
         }
      if(pid[i]==0)
         {
           //CODICE FIGLI
           printf("Sono il figlio %d\n",getpid());
 
           //metto nel *mio* vettore il mio pid
           pid[i]=getpid();
 
          //blocco il segnale SIGUSR1
          sigemptyset(&newmask);
          sigaddset(&newmask,SIGUSR1);
          sigprocmask(SIG_BLOCK,&newmask,NULL);
 
           //installo il gestore del sengale SIGUSR1
           sig.sa_handler = handler;
           sigemptyset(&sig.sa_mask);
           sig.sa_flags=0;        //non ho bisogno di flag particolari
           sigaction(SIGUSR1,&sig,NULL);
 
           //chiudo la mia pipe di scrittura dal lato di lettura
           close(pp[i][0]);
 
           //chiudo la mia pipe di lettura dal alto di scrittura
           close(pp[(i+1)%2][1]);
 
           //inizializzo il generatore di numero casuali e ne genero uno compreso tra 0 e N;
           srand(getpid());
           mynumero=rand()%N;
           printf("Figlio %d ha generato il numero %d\n",getpid(),mynumero);
 
 
           //scrivo il mio pid e il numero casuale
           if(write(pp[i][1],&pid[i],sizeof(int))<0)
             {
               perror("write pid");
               exit(-1);
             }
           if(write(pp[i][1],&mynumero,sizeof(int))<0)
             {
               perror("write numero");
               exit(-1);
             }
           //leggo pid e numero casuale dall'altro figlio
           if(read(pp[(i+1)%2][0],&pid[(i+1)%2],sizeof(int))<0)
             {
               perror("read pid");
               exit(-1);
             }
           if(read(pp[(i+1)%2][0],&numero,sizeof(int))<0)
             {
               perror("read numero");
               exit(-1);
             }
           //notare come la pipe sia il punto di sincronismo tra i due figli: per fare una
           //lettura/scrittura entrambi sevono essere arrivati a questo punto, e quindi hanno
           //anche il gestore dei segnali gia' pronto
 
 
           //se il mio numero e' minore di quello che ho ricevuto, o se sono
           //uguali ma il mio pid e' minore, mando un SIGUSR all'altro figlio
           if(mynumero<numero || (mynumero==numero && getpid()<pid[(i+1)%2]))
             {
               printf("Figlio %d manda un SIGUSR1 a %d\n",getpid(),pid[(i+1)%2]); 
               kill(pid[(i+1)%2],SIGUSR1);
             }
 
           //mi metto in attesa di un segnale qualunque
           //questo va bene sia per entrambi i figli
           //sig.sa_mask e' empty
           printf("Figlio %d si sospende...\n",getpid());
           sigsuspend(&(sig.sa_mask));
         }
    }
 
  //CODICE PADRE
 
  printf("Padre: ho pid %d, i figli sono %d %d\n",getpid(),pid[0],pid[1]);
 
  //chiudo entrambe le pipe, non mi servono
  close(pp[0][0]);
  close(pp[0][1]);
  close(pp[1][0]);
  close(pp[1][1]);
 
  //aspetto che il primo figlio esca (sara' quello che ha ricevuto SIGUSR1 dall'altro)
  exit_pid=wait(&status);
  if(exit_pid<0)
    {
      perror("wait");
      exit(-1);
    }
  printf("Padre: figlio %d uscito\n",exit_pid);
 
  //mando un sigusr1 al processo che e' ancora vivo
  kill( ((pid[0]==exit_pid) ? pid[1] : pid[0]) , SIGUSR1);
  printf("Padre: ho mandato una SIGUSR1 al figlio %d\n",((pid[0]==exit_pid) ? pid[1] : pid[0]));
 
  return 0;
 
}
 
 
/*
---IF aritmentico---
 
variabile = (condizione) ? valore1 : valore2; 
 
Questo e' equivalente a:
 
if(condizione)
  variabile=valore1:
else
  variabile=valore2;
 
 
 
---Resto---
L'operatore % da il resto di una divisione:
 
resto = dividendo%divisore;
 
ES.
0%2 = 0
1%2 = 1
2%2 = 0
3%2 = 1
4%2 = 0
5%2 = 1
ecc.
 
*/
 

 

 

6-SOA/esempi utili catalogati/c_ps/2006-11-29.c/*TESTO  2006-11-29
 
Si realizzi in ambiente Unix/C la seguente interazione tra processi:
 
-un processo determina il proprio pid P e procede a generare processi figli fintanto che il pid di un figlio Pf non assume valore 
 maggiore od uguale del pid del padre P maggiorato di 5 (cioe' Pf>=P+5). Discutere in quali condizioni il pid di un figlio e' maggiore
 del pid del padre;
-ogni processo figlio cosi' generato visualizza il proprio pid;
-il processo figlio con pid minore invia un segnale a tutti gli altri processi e poi termina visualizzando un messaggio di terminazione;
-gli altri figli non appena ricevono il segnale visualizzano un messaggio e terminano;
-il padre termina dopo che sono terminati tutti i figli
 
 
 
 
 
 
 
--SOLUZIONE--
 
Per quanto riguarda la domanda: il pid del figlio NON e' sempre maggiore di quello del padre. Infatti, dato che il pid e' rappresentato con 16 bit, puo'
accadere che si arrivi al pid 65536, dopo di che si ricomincia da 0 con il primo pid disponibile. Quindi, se per esempio il padre ha pid 65530 potrebbe generare 
due figli, uno 65533, uno 65536, e poi un terzo con pid, per esempio, 100 quindi minore di quello del padre.
 
PERO'... questa era la risposta alla domanda. Per lo svolgimento degli altri punti del compito era possibile fare un'ipotesi semplificativa (scrivendolo nel compito):
si suppone di non raggiungere mai il limite di 65536, e quindi si assumere che i pid dei figli siamo sempre maggiori di quelli del padre e sempre crescenti. 
Questa ipotesi NON viene penalizzata nel giudizio, era lecita. 
 
**La soluzione riportata qui sotto si basa su questa ipotesi.** 
 
In fondo c'e' una piccola nota con un abbozzo di soluzione nel caso piu' generale di pid non crescenti.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
 
 
 
 
//Funzione di gestione segnali
void handler(int signo)
{
  if(signo==SIGINT)
    {
      printf("Processo figlio %d ha ricevuto un SIGINT ed esce\n",getpid());
      exit(0);
    }
}
 
 
int main()
{
  struct sigaction sig;
  sigset_t newmask;
  int p[2],pid,i,j,status;
  //questo vettore conterra' i pid dei figli. Visto che li assumiamo crescenti, essi non saranno mai piu di 5...
  int pidV[5]; 
 
  //creo la pipe che usera' il padre per mandare i pid di tutti i figli al figlio con pid minore
  if(pipe(p)<0) 
    {
      perror("pipe");
      exit(-1);
    }
 
  //stampo il pid del padre
  printf("Sono il padre con pid %d\n",getpid());
 
  //Genero il primo figlio, quello che avra pid MINORE
  if((pidV[0]=fork())<0) //genero il primo figlio
    {
      perror("fork primo figlio");
      exit(-1);
    }
  if(pidV[0]==0) 
    {//CODICE DEL PRIMO FIGLIO
 
      //chiudo la pipe in scrittura
      close(p[1]);
 
      //stampo il pid
      printf("Sono il figlio %d\n",getpid());
 
      do{
         if(read(p[0],&pid,sizeof(pid))<0)
           {
             perror("read pid");
             exit(-1);
           }
         //se ho ricevuto il mio pid vuole dire che ho termianto e posso uscire
         //in pratica faro' in modo che il padre mi mandi i pid di tutti i figli in sequenza, ma con
         //quello del figlio minore per ultimo. Il figlio minore li leggere uno per uno con
         //la read, e manda un SIGINT fin tanto che non legge il suo pid, che e' il segnale che
         //i pid sono finiti e puo' uscire
         if(pid==getpid())
           break;
 
         //mando un SIGINT al figlio pid
         kill(pid,SIGINT);
      }
      while(1);
      printf("Figlio %d con pid minore esce\n",getpid());
 
      exit(0);
    }
 
 
  //CODICE DEL PADRE
 
  //chiudo la pipe in lettura
  close(p[0]);
 
  //Genero gli altri figli
  i=1;
  do
    {
      if((pidV[i]=fork())<0) //genero il figlio
         {
           perror("fork primo figlio");
           exit(-1);
         }
      if(pidV[i]==0)
         {
           //CODICE FIGLI
 
           //non mi servono le pipe;
           close(p[0]);
           close(p[1]);
 
          //blocco il segnale SIGINT
          sigemptyset(&newmask);
          sigaddset(&newmask,SIGINT);
          sigprocmask(SIG_BLOCK,&newmask,NULL);
 
           //installo il gestore del segnale SIGINT
           sig.sa_handler = handler;
           sigemptyset(&sig.sa_mask);
           sig.sa_flags=0;
           sigaction(SIGINT,&sig,NULL);
 
           //stampo il pid
           printf("Sono il figlio %d\n",getpid());
 
           //mi sospendo in attesa di qualunqe segnale
           sigsuspend(&(sig.sa_mask));
       
           //fine codice figli
         }
      //aspettiamo un po', nel frattempo potreste lanciare qualche processo (tipo un browser), giusto per non avere sempre i pid in perfetta sequenza...
      sleep(2);
    }
  while(pidV[i++]<(getpid()+5) && i<5);
 
  //CODICE PADRE
  //mando al figlio minore i pid di tutti i figli, lui compreso. Il suo pid pero' sara' l'ultimo... occhio agli indici!
  for(j=i-1;j>=0;j--)
    write(p[1],&(pidV[j]),sizeof(pidV[j]));
 
  //aspetto i figli che ho generato...
  for(j=0;j<i;j++)
    wait(&status);
 
  return 0;
}
 
 
/*
SOLUZIONE CASO GENERALE
 
Si poteva procedere in questo modo: tutti i figli vengono generati nello stesso modo in un ciclo do-while come quello a riga 121. Il padre, una volta raggiunta 
la condizione di uscita, guarda quale dei figli ha il pid piu' piccolo e gli manda un SIGUSR1, e poi fa una write sulla pipe uguale a quella alla riga 157. Avro' 
precedentemente installato il gestore SIGUSR1 per tutti i figli, nel quale e' contenuto qualcosa di questo tipo:
 
if(signo==SIGUSR1)
{
do{
  if(read(p[0],&pid,sizeof(pid))<0)
  {
   perror("read pid");
   exit(-1);
  }
 
  if(pid==getpid())
    break;
 
  //mando un SIGINT al figlio pid
  kill(pid,SIGINT);
  }
while(1);
printf("Figlio %d con pid minore esce\n",getpid());
 
exit(0);    
}
 
Cioe' esattamente quello che fa il primo figlio nella soluzione precedente. Ovviamente si dovranno dichiarere tutte le variabili necessaria globabli, ecc. ecc.
 
Il ciclo di generazione figli cambia in questo modo: si elimina tutta la parte dalla riga 76 alla 111 (generazione del primo figlio), si parte con i=0 e si
toglie la condizione i<5. Naturalmente e' necessario usare un vettore pidV molto piu' grande, direi che, per quello detto all'inizio, di 65536 dovrebbe bastare.
Se a qualcuno interssa mi faccia sapere, che possiamo guardare questa soluzione in dettaglio.
 
*/
 

 

 

7-SOA/esempi utili catalogati/c_ps/2007-01-23.c/* TESTO 2007-01-23
Prova UNIX:
Si realizzi in ambiente Unix/C il server della seguente interazione tra processi:
-il sistema consiste di un processo server Ps e dei processi clienti Pci; per la
comunicazione tra Ps e i processi clienti Pci vengono utilizzate socket di tipo Stream;
la porta su cui il server Ps offre il servizio va scelta tra la 207 e la 2007, inserendo in
un commento la motivazione.
-il client invia al server una stringa che rappresenta un numero N con 1  N  4.
-il processo server Ps fornisce un servizio concorrente : il figlio creato per servire una
connessione deve creare N processi Pni che visualizzano il proprio PID e terminano;
-il client deve ricevere un messaggio di tipo stringa contenente i PID degli N processi
Pni;
Si consideri anche l'estensione di far generare a ciascuno degli N processi Pni un
numero casuale (rappresentato come stringa) che deve essere trasmesso al cliente insieme al
PID del processo. Come client si utilizzi il comando "telnet nomehost porta".
*/
/* NOTA
Il codice commentato e indicato con ESTENSIONE realizza la funzionalita' richiesta nell'estensione
del testo
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
 
#define PORT 2007 //le porte sotto il 1024 sono riservate al sistema operativo
 
int main()
{
  char buffer[256];
  int pidV[4]; //un vettore per i pid dei processi Pni, che saranno al massimo 4
  struct sockaddr_in server,client;
  int sock,msgsock;
  int lenght,pid,N,i;
 
  /*ESTENSIONE
    int p[2],nrand;
  */
 
  //stampo il pid del padre
  printf("Sono il padre con pid %d\n",getpid());
 
  sock=socket(AF_INET,SOCK_STREAM,0); //creo la socket
  if(sock<0)
    {
      perror("creazione stream socket");
      exit(-1);
    }
  //preparo la struttura sockaddr_in per settare i parametri della socket
  server.sin_family=AF_INET;         //internet protocol
  server.sin_addr.s_addr=INADDR_ANY; //ascolto da tutte le interfacce
  server.sin_port=htons(PORT);       //e dalla porta specificata
  if(bind(sock,(struct sockaddr *)&server,sizeof(server))<0)
    {
      perror("binding stream socket");
      exit(-1);
    }
  printf("Server socket port # %d\n",ntohs(server.sin_port));
 
  listen(sock,5); //massimo di 5 connesioni in attesa
 
  //ciclo infinito del server concorrente
  do
    {
      printf("Accept nel server...\n");
      msgsock=accept(sock,(struct sockaddr *)&client,(socklen_t *)&lenght); //attendo connesioni...
      if(msgsock == -1)
         {
           perror("accept");
           exit(-1);
         }
 
      if((pid=fork())<0)  //creo il figlio gestore della connessione
         {
           perror("fork figlio");
           exit(-1);
         }
      else
         if(pid==0) //sono il figlio?
           {
             //CODICE FIGLIO GESTORE
             printf("Figlio gestore con pid %d\n",getpid());
 
             //non mi serve piu' questo descrittore
             close(sock);
 
             /*ESTENSIONE
               if(pipe(p)<0) 
               {
               perror("pipe");
               exit(-1);
               }
             */
 
             //ciclo del gestore: deve continuamente leggere dalla socket i messaggi che il Pclient gli manda
             do
               {
                 if(read(msgsock,buffer,256)<0) //leggo il numero di processi Pni da creare
                   perror("reading message");
 
                 N=(int)(buffer[0]-'0'); //lo metto in un numero
                 if(N<1 || N>4) //e' un numero valido?
                   {
                     printf("Figlio %d : il cliente mi ha mandato il numero %d non valido, esco.\n",getpid(),N); 
                     exit(-1);
                   }
 
                 printf("Figlio %d : il cliente mi ha mandato %d\n",getpid(),N); 
                 sprintf(buffer,"Processi Pni ");
 
                 //ciclo di creazione dei Pni
                 for(i=0;i<N;i++)
                   {
                     if((pidV[i]=fork())<0)
                       {
                          perror("fork figlio del gestore");
                          exit(-1);
                       }
                     else
                       if(pidV[i]==0) //sono il figlio?
                          {
                            //CODICE figlio Pni
                            close(msgsock); //non mi serve piu'
                            printf("Figlio del gestore %d con pid %d\n",getppid(),getpid());
                            /*ESTENSIONE
                              close(p[0]);
                              srand(getpid()); //inizializzo il generatore di numeri casuali
                              nrand=rand()%10; //numero casuale da 0 a 9
                              printf("Numero casuale di %d = %d\n",getpid(),nrand);
                              write(p[1],&nrand,sizeof(nrand));
                            */
                            exit(-1);
                          }
                     /* ESTENSIONE
                        read(p[0],&nrand,sizeof(nrand)); //leggo dal figlio Pni il suo numero casuale
                        sprintf(buffer,"%s Pid=%d con numero casuale %d ",buffer,pidV[i],nrand);
                     */
                     sprintf(buffer,"%s Pid=%d ",buffer,pidV[i]); //da commentare nella versione con ESTENSIONE!!!
                   }
                 printf("Figlio %d manda al clinent la stringa: %s\n",getpid(),buffer);
                 if(write(msgsock,&buffer,strlen(buffer)+1)<0) //spedisco al client la risposta
                   perror("writing message");
               }
             while(1);//ciclo del figlio gestore della connessione
           }
 
      //CODICE PADRE
      close(msgsock);
    }
  while(1);//ciclo del server padre
 
  return 0;
}

 

 

8-SOA/esempi utili catalogati/c_ps/2007-02-20.c/*TESTO 2007-02-20
Scrv un prog che:
 
- Se invocato senza parametri sulla riga di comando
entra in un ciclo infinito in cui visualizza un carattere punto ogni
2 secondi.
 
 
- Se invocato con un solo parametro, invia  un segnale SIGUSR1 al processo
  il cui pid è specificato come parametro, affinche' esso riduca di 200 millisecondi il periodo di
  visualizzazione del carattere punto.
 
 
  - Se invocato con due parametri, invia un segnale SIGUSR2 al processo
  il cui pid è specificato come primo parametro, attende un
  numero di secondi pari al valore del secondo parametro, per poi inviare un
  segnale SIGUSR1 al processo con il pid specificato ; il processo che
  ha ricevuto un segnale SIGUSR2 deve porsi esplicitamente in attesa di
  un nuovo segnale SIGUSR1 prima di poter proseguire con la
  visualizzazione del carattere punto.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
 
 
unsigned long attendiMicro=2000000; //2 secondi in microsecondi
unsigned long decrementaMicro=200000; //200ms in microsecondi (provare a metterlo anche a 500ms, o 1 secondo, per rendere piu' visibile l'effetto...)
 
//Funzione di gestione segnali
void handler(int signo)
{
  sigset_t s;
 
  switch(signo)
    {
    case SIGUSR1 :
      printf("\nProcesso %d ha ricevuto un SIGUSR1\n",getpid());
      fflush(NULL);
 
      //decremento il numero di microsecondi che devo attendere
      attendiMicro=(attendiMicro-decrementaMicro)>0 ? (attendiMicro-decrementaMicro) : attendiMicro;
 
      break;
 
    case SIGUSR2:
      printf("\nProcesso %d ha ricevuto un SIGUSR2... attendo SIGUSR1\n",getpid());
      fflush(NULL);
 
      //blocco tutti i segnali, eccetto SIGUSR1 e i non bloccabili (SIGKILL e SIGSTOP)
      //
      //non e' strettamente necessario, andava bene anche con tutti i segnali abilitati, tramite una semplice
      //sigemptyset(&s). Diciamo che in questo modo impedisco ad altri segnali non gestiti di interrompere il processo,
      //ma soprattutto ad un eventuale SIGUSR2 di interferire
      sigfillset(&s);
      sigdelset(&s,SIGUSR1);
      //attendo esplicitamente il segnale SIGUSR1 prima di proseguire...
      sigsuspend(&s);
 
      break;
    }
}
 
 
 
int main(int argc, char *argv[])
{
  struct sigaction sig;
  int N1,N2;
 
 
  //se argc==1 vuole dire che non avevamo nessun argomento da linea di comando
  if(argc==1)
    {
      //installo il gestore per SIGUSR1 e SIGUSR2
      sig.sa_handler = handler;
      sigemptyset(&sig.sa_mask);
 
      //blocco il SIGUSR2 durante l'esecuzione dell'handler SIGUSR1, per sicurezza. Non era richiesto.
      sigaddset(&sig.sa_mask,SIGUSR2);
      //come sopra, blocco il SIGUSR1 durante l'esecuzione dell'handler SIGUSR2, anche questo non richiesto. 
      //Domanda: perche' funziona lo stesso?
      sigaddset(&sig.sa_mask,SIGUSR1);
 
      sig.sa_flags=0;
      sigaction(SIGUSR1,&sig,NULL);
      sigaction(SIGUSR2,&sig,NULL);
 
      printf("Processo %d attende indefinitamente",getpid());
      fflush(NULL); //altrimenti non vedete nulla...
      while(1) 
         {
           printf(".");
           fflush(NULL);//altrimenti non vedete nulla...
 
           //uso una usleep per poter apprezare i millisecondi, e poter effettuale il decremento richiesto quando arriva il SIGUSR1
           //la sleep non poteva andare bene, in quando accetta solo secondi interi
           usleep(attendiMicro);
         }
    }
 
  //se ho almeno un argomento da linea di comando...
  if(argc>=2)
    {
      //leggo il pid a cui dovro' mandare i segnali
      N1=atoi(argv[1]);
      if(N1<=0)
         {
         printf("ERRORE negli argomenti\nUso: programma <N1> <N2>\nN1 e N2 parametri facoltativi. N1 deve essere un pid valido, N2 un numero intero maggiore di zero.\n");
         exit(-1);
         }
 
      //ho 2 (o piu')  argomenti?
      if(argc>=3)
         {
           //leggo i secondi che dovro' attendere
           N2=atoi(argv[2]);
           if(N2<=0)
             {
               printf("ERRORE negli argomenti\nUso: programma <N1> <N2>\nN1 e N2 parametri facoltativi. N1 deve essere un pid valido, N2 un numero intero maggiore di zero.\n");
               exit(-1);
             }
           printf("Processo %d manda un SIGUSR2 a %d...",getpid(),N1);
           kill(N1,SIGUSR2);
 
           printf("e attende %d secondi...\n",N2);
           fflush(NULL);//altrimenti non vedete nulla...
           sleep(N2);
         }
 
     printf("Processo %d manda un SIGUSR1 a %d\n",getpid(),N1);
     kill(N1,SIGUSR1);
    }
  return 0;
}
 
/*
---IF aritmentico---
 
variabile = (condizione) ? valore1 : valore2; 
 
Questo e' equivalente a:
 
if(condizione)
  variabile=valore1:
else
  variabile=valore2;
*/

 
 

 

9-SOA/esempi utili catalogati/c_ps/2007-07-23.c/* TESTO 2007-07-23
 
Si realizzi un SERVER concorrente su socket STREAM che abbia il seguente comportamento:
 
- il processo server ricevce dal client un singolo messaggio con un numero variabile n (2<= n <= 10) di linee di testo,
  in cui la prima contiene il nume di un comando UNIX, e terminate da una linea contenente  unicamente la parola chiave
  "STOP"; Esempio: (n=5)
 
  sort
  1 2 3
  4 5 6
  7 8 9
  STOP
 
- se n>2 il server provvede a memorizzare in un file temporaneo il contenuto delle righe intermedie (linee 2... n-1) del
  messaggio ricevuto per renderlo disponibilie come argomento al momento dell'esecuzione del comando indicato dal client;
 
- l'output (stdout e stderr) generato dal comendo deve essere inviato al client
 
- al termine dell'esecuzione del comando il file temporaneo deve essere rimosso
 
- dopo aver ricevuto un segnale SIGUSR1 il server deve iniziare  a visualizzare sul suo stdout l'indirizzo di ogni cliente
  che si connette, cessando tale comportamento alla notifica di un segnale SIGUSR2
 
Si siggerisce l'utilizzo di telnet come client.
*/
 
 
 
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <string.h>
 
 
//una porta a caso
#define PORT 9001
 
//descrittore del file server-log.txt
int scriviIndirizzo=0;
 
 
 
//Funzione di gestione segnali SIGUSR1 e SIGUSR2
void handler(int signo)
{
  if(signo == SIGUSR1)
    scriviIndirizzo=1;
  else
    scriviIndirizzo=0;
}
 
 
 
 
int main()
{
  char * env[]={NULL,NULL,(char *)0};
  char buffer[256]="",nomeFile[256]="",comando[256]="";
  struct sigaction sig;
  struct sockaddr_in server,client;
  int sock,msgsock;
  int lenght;
  int pid,f,n=0,j=0;
 
  printf("Sono il server con pid %d\n",getpid());
 
  //SOCKET //////////////////////
  //
  //preparo la struttura sockaddr_in per settare i parametri della socket
  sock=socket(AF_INET,SOCK_STREAM,0); //creo la socket
  if(sock<0)
    {
      perror("creazione stream socket");
      exit(-1);
    }
 
  //preparo la struttura sockaddr_in per settare i parametri della socket
  server.sin_family=AF_INET;         //internet protocol
  server.sin_addr.s_addr=INADDR_ANY; //ascolto da tutte le interfacce
  server.sin_port=htons(PORT);       //e dalla porta specificata
  if(bind(sock,(struct sockaddr *)&server,sizeof(server))<0)
    {
      perror("binding stream socket");
      exit(-1);
    }
 
  //leggo la porta che mi e' stata effettivamente assegnata
  lenght=sizeof(server);
  if(getsockname(sock,(struct sockaddr *)&server,(socklen_t *)&lenght)<0)//leggo il nome della socket
    {
      perror("getting socket name");
      exit(-1);
    }
 
  printf("Socket port # %d\n",ntohs(server.sin_port));
 
  listen(sock,5); //massimo di 5 connesioni in attesa
  ////////////////////////////////
 
 
  //SEGNALI //////////////////////
  //
  sig.sa_handler = handler; //gestore del segnale SIGUSR1
  sigemptyset(&sig.sa_mask);
  sigaddset(&sig.sa_mask,SIGUSR2); //blocco SIGUSR2 durante l'esecuzione dell'handler
  sig.sa_flags=SA_RESTART;
 
  sigaction(SIGUSR1,&sig,NULL);
 
  sig.sa_handler = handler; //gestore del segnale SIGUSR2
  sigemptyset(&sig.sa_mask);
  sigaddset(&sig.sa_mask,SIGUSR1); //blocco SIGUSR1 durante l'esecuzione dell'handler
 
  sigaction(SIGUSR2,&sig,NULL);
  ////////////////////////////////
 
  //ciclo infinito del server in attesa di connessioni
  do
    {
 
      msgsock=accept(sock,(struct sockaddr *)&client,(socklen_t *)&lenght);//attendo connesioni...
      if(msgsock == -1)
         {
           perror("accept");
           exit(-1);
         }
 
      //se e' stato ricevuto il segnale SIGUSR1 allora stampo le info del client
      if(scriviIndirizzo)
         printf("Connection from %s, port %d\n",inet_ntoa(client.sin_addr), ntohs(client.sin_port));
 
      if((pid=fork())<0)  //creo il figlio che gestira' la connessione
         {
           perror("fork figlio gestore connessione");
           exit(-1);
         }
      if(pid==0) //sono il figlio?
         {
           /////////////////////////////
           //CODICE FIGLIO GESTORE
 
           printf("Sono il gestore della connessione, ho pid %d\n",getpid());
 
           //preparo il nome del file temporaneo.
           //e' meglio che il nome del file sia sempre diverso, con un nome specifico per ogni gestore. 
           //In questo modo evitiamo che diversi figli/gestori scrivano e leggano dallo stesso file. 
           //Usiamo il pid
           memset(nomeFile,0,sizeof(nomeFile));
           sprintf(nomeFile,"%d.txt",getpid());
 
           f=open(nomeFile,O_CREAT | O_RDWR | O_TRUNC,0666);
 
           //continua a leggere le stringhe del client, fino a quando non riceve "STOP" o non ne ha lette 10
           do
             {
               //resetto i buffer
               memset(buffer,0,sizeof(buffer));
               j=0;
 
               //faccio un ciclo per leggere la riga che mi manda il client, carattere per carattere
               do
                 {
                   //leggo la stringa che mi manda il client caratte per carattere
                   if(read(msgsock,&buffer[j],1)<0)
                     {
                       perror("reading");
                       exit(-1);
                     }
                 }
               while(buffer[j++]!='\n');
 
               //se ho ricevuto la stringa STOP e almeno un'altra stringa (n>=1), esco
               if(!strcmp(buffer,"STOP\r\n") && n)
                 break;
 
               //se e' la prima riga che leggo allora la salvo in comando
               if(!n)
                 {
                   //elimino l'eventuale \r e \n, che non piaciono molto a execvp
                   if(strchr(buffer,'\r')) strchr(buffer,'\r')[0]=0x0;
                   if(strchr(buffer,'\n')) strchr(buffer,'\n')[0]=0x0;
                   strcpy(comando,buffer);
                 }
               else //altrimenti la salvo nel file
                 if(write(f,buffer,strlen(buffer))<0)
                   {
                     perror("writing argomenti");
                     exit(-1);
                   }
 
             }
           while(++n<9); //controllo quante linee ho ricevuto, alla decima esco in ogni caso
 
           //chiudo il file in modo che salvi le modifiche
           close(f);
 
           if((pid=fork())<0)  //creo il NIPOTE eseguira' il comando
             {
               perror("fork figlio gestore connessione");
               exit(-1);
             }
           if(pid==0) //sono il figlio del gestore (nipote del padre)?
             {
               /////////////////////////////
               //CODICE NIPOTE
 
               printf("Eseguo il comando %s\n",comando);
               fflush(NULL);
 
               //chiudo stdout e stderr
               close(1);
               close(2);
 
               //il nuovo stdout e' la socket
               if(dup(msgsock)<0)
                 perror("dup1");
 
               //il nuovo stderr e' la socket
               if(dup(msgsock)<0)
                 perror("dup1");
 
               close(msgsock);
 
               env[0]=comando;
               env[1]=nomeFile;
               if(execvp(comando,env)<0)
                 perror("execvp");
               /////////////////
             }
 
           //il gestore attende che il nipote abbia finito di eseguire il comando
           wait(NULL);
 
           //elimino il file temporaneo
           if(unlink(nomeFile)<0)
            perror("unlink");
 
           close(msgsock);
 
           //faccio uscire il figlio
           exit(0);
           ////////////////////////////
         }
      close(msgsock);
    }
  while(1);
 
 
  return 0;
}

 

 

10-SOA/esempi utili catalogati/c_ps/2007-07-23-easy.c/*    2007-07-23 easy **** ATTENZIONE ******
 *  Questa e' una versione semplificata della soluzione, che funziona solo se il client e' telent!
 *   
 *    Il problema sta nella read alla riga 187: con un generico client potrei inviare tutti i dati in unica stringa
 *    (es.sort\n1 2 3\n4 5 6\n7 8 9\nSTOP), il che renderebbe non funzionante il ciclo indicato sotto.
 *    Per fortuna telnet invia subito la riga quando premete invio editandola, quindi ci semplifica abbastanza le cose,
 *    ma non e' la soluzione piu' ortodossa.
 *    
 */
 
 
/* TESTO
 
Si realizzi un SERVER concorrente su socket STREAM che abbia il seguente comportamento:
 
- il processo server ricevce dal client un singolo messaggio con un numero variabile n (2<= n <= 10) di linee di testo,
  in cui la prima contiene il nume di un comando UNIX, e terminate da una linea contenente  unicamente la parola chiave
  "STOP"; Esempio: (n=5)
 
  sort
  1 2 3
  4 5 6
  7 8 9
  STOP
 
- se n>2 il server provvede a memorizzare in un file temporaneo il contenuto delle righe intermedie (linee 2... n-1) del
  messaggio ricevuto per renderlo disponibilie come argomento al momento dell'esecuzione del comando indicato dal client;
 
- l'output (stdout e stderr) generato dal comendo deve essere inviato al client
 
- al termine dell'esecuzione del comando il file temporaneo deve essere rimosso
 
- dopo aver ricevuto un segnale SIGUSR1 il server deve iniziare  a visualizzare sul suo stdout l'indirizzo di ogni cliente
  che si connette, cessando tale comportamento alla notifica di un segnale SIGUSR2
 
Si siggerisce l'utilizzo di telnet come client.
*/
 
 
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <arpa/inet.h>
 
 
//una porta a caso
#define PORT 9001
 
//variabile che indica se dobbiamo o meno stampare l'indirizzo del client
int scriviIndirizzo=0;
 
 
 
//Funzione di gestione segnali SIGUSR1 e SIGUSR2
void handler(int signo)
{
  if(signo == SIGUSR1)
    scriviIndirizzo=1;
  else
    scriviIndirizzo=0;
}
 
 
 
 
int main()
{
  char buffer[256]="",nomeFile[256]="",comando[256]="";
  struct sigaction sig;
  struct sockaddr_in server,client;
  int sock,msgsock;
  int lenght;
  int pid,f,i=0;
 
  printf("Sono il server con pid %d\n",getpid());
 
  //SOCKET //////////////////////
  //
  //preparo la struttura sockaddr_in per settare i parametri della socket
  sock=socket(AF_INET,SOCK_STREAM,0); //creo la socket
  if(sock<0)
    {
      perror("creazione stream socket");
      exit(-1);
    }
 
  //preparo la struttura sockaddr_in per settare i parametri della socket
  server.sin_family=AF_INET;         //internet protocol
  server.sin_addr.s_addr=INADDR_ANY; //ascolto da tutte le interfacce
  server.sin_port=htons(PORT);       //e dalla porta specificata
  if(bind(sock,(struct sockaddr *)&server,sizeof(server))<0)
    {
      perror("binding stream socket");
      exit(-1);
    }
 
  //leggo la porta che mi e' stata effettivamente assegnata
  lenght=sizeof(server);
  if(getsockname(sock,(struct sockaddr *)&server,(socklen_t *)&lenght)<0)//leggo il nome della socket
    {
      perror("getting socket name");
      exit(-1);
    }
 
  printf("Socket port # %d\n",ntohs(server.sin_port));
 
  listen(sock,5); //massimo di 5 connesioni in attesa
  ////////////////////////////////
 
 
  //SEGNALI //////////////////////
  //
  sig.sa_handler = handler; //gestore del segnale SIGUSR1
  sigemptyset(&sig.sa_mask);
  sigaddset(&sig.sa_mask,SIGUSR2); //blocco SIGUSR2 durante l'esecuzione dell'handler
  sig.sa_flags=SA_RESTART;
 
  sigaction(SIGUSR1,&sig,NULL);
 
  sig.sa_handler = handler; //gestore del segnale SIGUSR2
  sigemptyset(&sig.sa_mask);
  sigaddset(&sig.sa_mask,SIGUSR1); //blocco SIGUSR1 durante l'esecuzione dell'handler
 
  sigaction(SIGUSR2,&sig,NULL);
  ////////////////////////////////
 
  //ciclo infinito del server in attesa di connessioni
  do
    {
 
      msgsock=accept(sock,(struct sockaddr *)&client,(socklen_t *)&lenght);//attendo connesioni...
      if(msgsock == -1)
         {
           perror("accept");
           exit(-1);
         }
 
      //se e' stato ricevuto il segnale SIGUSR1 allora stampo le info del client
      if(scriviIndirizzo)
         printf("Connection from %s, port %d\n",inet_ntoa(client.sin_addr), ntohs(client.sin_port));
 
      if((pid=fork())<0)  //creo il figlio che gestira' la connessione
         {
           perror("fork figlio gestore connessione");
           exit(-1);
         }
      if(pid==0) //sono il figlio?
         {
           /////////////////////////////
           //CODICE FIGLIO GESTORE
 
           printf("Sono il gestore della connessione, ho pid %d\n",getpid());
 
           //preparo il nome del file temporaneo.
           //e' meglio che il nome del file sia sempre diverso, con un nome specifico per ogni gestore. 
           //In questo modo evitiamo che diversi figli/gestori scrivano e leggano dallo stesso file. 
           //Usiamo il pid
           memset(nomeFile,0,sizeof(nomeFile));
           sprintf(nomeFile,"%d.txt",getpid());
 
           f=open(nomeFile,O_CREAT | O_RDWR | O_TRUNC,0666);
 
           //leggo la stringa che mi manda il client contenente il comando da eseguire
           if(read(msgsock,comando,sizeof(comando))<0)
             {
               perror("reading comando");
               exit(-1);
             }
 
           //continua a leggere le stringhe del client salvandole in un file, fino a quando non riceve "STOP"
           do
             {
               //resetto i buffer
               memset(buffer,0,sizeof(buffer));
 
               //leggo la stringa che mi manda il client con il comando da eseguire
               //FUNZIONE SOLO SE IL CLIENT E' TELNET!!
               if(read(msgsock,buffer,sizeof(buffer))<0)
                 {
                   perror("reading argomenti");
                   exit(-1);
                 }
 
               //se ho ricevuto la stringa STOP esco
               if(!strcmp(buffer,"STOP\r\n"))
                 break;
 
               //scrivo l'argomento nel file
               if(write(f,buffer,strlen(buffer))<0)
                 {
                   perror("writing message");
                   exit(-1);
                 }
             }
           while(++i<9); //controllo quante linee ho ricevuto, alla decima esco
 
           //chiudo il file in modo che salvi le modifiche
           close(f);
 
           //elimino i caratteri aggiungi da telnet (\r\n), che non piaciono a execv
           comando[strlen(comando)-2]=0x0;
 
          //preparo la stringa con il comando piu' argomento
          sprintf(comando,"%s %s",comando,nomeFile);
 
           printf("Eseguo il comando %s\n",comando);
           fflush(NULL);
 
           //chiudo stdout e stderr
           close(1);
           close(2);
 
           //il nuovo stdout e' la socket
           if(dup(msgsock)<0)
             perror("dup1");
 
           //il nuovo stderr e' la socket
           if(dup(msgsock)<0)
             perror("dup1");
 
           close(msgsock);
 
           //in questo modo torna nel programma e posso cancellare il file tmp
           if(system(comando)<0)
             perror("sistem");
 
           //elimino il file temporaneo
           if(unlink(nomeFile)<0)
            perror("unlink");
 
           //faccio uscire il figlio
           //questo fara' uscire anche telnet, come richiesto nel testo
           exit(0);
           ////////////////////////////
         }
      close(msgsock);
    }
  while(1);
 
 
  return 0;
}

 


 

 

11-SOA/esempi utili catalogati/c_ps/2007-09-11.c//   2007-09-11 ESEMPIO DI SOLUZIONE DI UNO STUDENTE
//
//
//file
#include <sys/stat.h>
//socket
#include <sys/socket.h>
//printf
#include <string.h>
#include <stdio.h>
//exit
#include <stdlib.h>
#include <netinet/in.h>
//file
#include <netdb.h>
//file
#include <fcntl.h>
#include <arpa/inet.h>
//segnali affidabili,kill
#include <signal.h>
//fork,segnali,pipe,file,sleep,alarm,pause
#include <unistd.h>  
//nanosleep
#include <time.h> 
//fork,getpid(),waitpid(),socket,file
#include <sys/types.h> 
//wait,waitpid()
#include <sys/wait.h>
 
void error(char *msg)
{
    perror(msg);
    exit(0);
}
 
int main(){
 
srand(time(NULL));
 
//P1
int P1,P2;
int piped[2];
int c,j;
if(pipe(piped)<0) 
    {
      perror("pipe");
      exit(-1);
    }
 
 
 
P1=getpid();
 
if ((P2=fork()) < 0)
    {
      perror("fork error");
      exit(1);
    }
  else
   if (P2 == 0)  //P2     
    {
         sleep(5); // attende 5 sec
         
         //Generazione di 5 figli
int pid;
for(j=0;j<5;j++){
         if ((pid=fork()) < 0)
                  {
                          perror("fork error");
                           exit(1);
                   }
                 else
                 if (pid == 0)    //figlio 
                 {
 
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char send_buffer[256];
char rec_buffer[256]="";
 
portno = 10000+j;
 
printf("Figlio di P2 con pid=%d :provo a comunicare con P1 tramite la porta %d\n",getpid(), portno);
 
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
    error("ERRORE in apertura");
server = gethostbyname("localhost");
if (server == NULL) {
    fprintf(stderr,"ERRORE, l’host non esiste\n");
    exit(0);
}
serv_addr.sin_family = AF_INET;
memcpy((char *)&serv_addr.sin_addr,(char *)server->h_addr,server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
    sleep(-1);//se non c'e' una connesione sospende il processo
 
int PID;
PID=getpid();
n = write(sockfd,&PID,sizeof(int));
 
if (n < 0)
     error("ERRORE in scrittura sulla socket");
 
printf("Figlio di P2 con pid=%d: sono riuscito a connettermi con P1 tramite la porta %d e termino\n",getpid(), portno);
close(sockfd);
exit(0);
                 }
 
//P2
write(piped[1], &pid, sizeof (int));
         }
 
//P2
 
printf("P2:ho generato 5 figli. Adesso aspetto che terminino\n");
while ((waitpid(-1, NULL, 0)) > 0);
printf("P2:Sono terminati tutti i miei figli; ora termino anche io\n");
exit(0);
 
        
}
  else      //P1
    {
 
int sockfd, newsockfd, portno, clilen, PID;
struct sockaddr_in serv_addr, cli_addr;
 
 
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
   error("ERRORE DI APERTURA DELLA SOCKET");
 
portno = 10000+rand() %5; // portno e' un numero casuale fra 10000 e 10004
 
 
 
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
         sizeof(serv_addr)) < 0)
         error("ERRORE DI BINDING");
listen(sockfd,5);
clilen = sizeof(cli_addr);
 
printf("P1:sto in ascolto sulla porta %d\n",portno);
 
newsockfd = accept(sockfd,
            (struct sockaddr *) &cli_addr,
            &clilen);
if (newsockfd < 0)
     error("ERRORE DI ACCEPT");
int n;
 
 
 
n = read(newsockfd,&PID,sizeof(int));
if (n < 0) perror("ERRORE in lettura dalla socket");
 
printf("P1:Ho recevuto un client di PID %d\n",PID);
 
int PidX;
 
for(j=0;j<5;j++){
 
n = read(piped[0],&PidX, sizeof (int));
if (n < 0) perror("ERRORE in lettura dalla socket");
 
if (PidX!=PID) {
printf("P1 :Mando un seganle SIGKILL al figlio con Pid %d per terminarlo\n",PidX);
kill(PidX,SIGKILL);
}
}
 
close(sockfd);
close(newsockfd);
 
printf("P1:Aspetto che P2 termini\n");
 
while ((wait(NULL)) > 0);
printf("P1: P2 e' terminato; termino anche io\n");
 
}
 
 
}

 

3.         

12-SOA/esempi utili catalogati/c_ps/2007-11-23.c/* TESTO
Si realizzi un programma in C che abbia il seguente comportamento:
- il processo genera due processi figli;
- il primo processo figlio entra in un ciclo infinito durante il quale visualizza a video un carattere asterisco (*) al secondo;
- il secondo processo figlio entra in un ciclo infinito durante il quale visualizza a video un carattere punto (.) al secondo;
- il processo padre attende indefinitamente: all’arrivo di un segnale SIGUSR1, termina i figli e termina anch’esso.
- a fronte della ricezione di un segnale SIGUSR1 da parte di uno qualunque dei due figli, ENTRAMBE le visualizzazioni dei 
  caratteri da parte dei processi devono arrestarsi. La ricezione da parte di uno qualunque dei due figli di un segnale SIGUSR2 
  deve riavviare ENTRAMBE le visualizzazioni.
 
Devono essere utilizzate le primitive per la gestione affidabile dei segnali.
 
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <arpa/inet.h>
 
//flag che abilita la scrittura
int abilitaScrittura=1;
//vettore dei pid
int pid[2];
//pid dell'altro processo
int altroPid=0;
//Funzione di gestione segnali SIGUSR1 e SIGUSR2
//
//ATTENZIONE
//
//L'idea e' questa: quando un processo (es. P1) riceve un segnale, modofica il PROPRIO flag di abilitazione
//scrittua e inoltra lo stesso segnale all'altro figlio (es. P2), in modo che possa a sua volta modificare
//il proprio flag. Bisogna fare attenzione che, quando l'altro figlio (es. P2)riceve il segnale inoltrato, oltre che 
//modificare il proprio flag, vorra a volta inoltrare il segnale, in quanto non sa se gli e' arrivato
//dall'esterno (utente) o dall'altro figlio (es. P1). Ci sono due modi per fare questo:
//1) usare il flag SA_SIGINFO. In questo modo handler viene chiamato con 3 parametri, di cui uno e' uno struct che
//   contiene il pid del processo che ha mandato il segnale (vedi "man sigaction" e flag SA_SIGINFO
//2) controllando il proprio flag, meno elegante e sicuro, ma piu' semplice
//
//In questa soluzione usiamo il metodo 2
//
void handler(int signo)
{
  printf("Ricevuto segnale\n");
 
  if(!pid[0] || !pid[1]) //se non sono il padre
    {
      if(signo == SIGUSR1)
         {
           if(abilitaScrittura)
             {
               abilitaScrittura=0;
               kill(altroPid,SIGUSR1);
             }
         }
      else
         {
           if(!abilitaScrittura)
             {
               abilitaScrittura=1;
               kill(altroPid,SIGUSR2);
             }
         }
    }
  else //sono il padre
    {
      //uccido i figli
      kill(pid[0],SIGKILL);
      kill(pid[1],SIGKILL);
 
      //attendo i figli
      wait();
    }
}
 
int main()
{
  struct sigaction sig;
  sigset_t mask;
  int i=0,p[2];
 
  ////////////////////////////////////////////
  //SEGNALI
  sig.sa_handler=handler; //gestore del segnale
  sig.sa_flags=SA_RESTART;
  sigemptyset(&sig.sa_mask);
  sigaddset(&sig.sa_mask,SIGUSR2); //blocco SIGUSR2 durante l'esecuzione dell'handler
 
  sigaction(SIGUSR1,&sig,NULL);
 
  sigemptyset(&sig.sa_mask);
  sigaddset(&sig.sa_mask,SIGUSR1); //blocco SIGUSR1 durante l'esecuzione dell'handler
 
  sigaction(SIGUSR2,&sig,NULL);
  //////////////////////////////////////////
 
  //creo la pipe
  if(pipe(p)<0)
    perror("pipe");
 
  printf("Padre con pid %d\n",getpid());
 
  for(i=0;i<2;i++)
    {
      if((pid[i]=fork())<0)  //creo il figlio che gestira' la connessione
         {
           perror("fork figlio");
           exit(-1);
         }
      if(pid[i]==0) //sono il figlio?
         {
           /////////////////////////////
           //CODICE FIGLIO i-esimo
 
           printf("Figlio %d con pid %d\n",i,getpid());
 
           //leggo l'altro pid
           if(read(p[0],&altroPid,sizeof(altroPid))<0)
             perror("read altro pid");
 
           //ciclo di scrittura
           while(1)
             {
               //sono abilitato?
               if(abilitaScrittura)
                 printf("%c",i==0 ? '*' : '.');
               fflush(NULL);
 
               //attendo un secondo
               sleep(1);
             }
           ////////////////////////////
         }
    }
  //scrivo al primo figlio il pid del secondo
  if(write(p[1],&pid[1],sizeof(pid[1]))<0)
    perror("write secondo pid");
  //scrivo al secondo figlio il pid del primo
  if(write(p[1],&pid[0],sizeof(pid[0]))<0)
    perror("write primo pid");
 
  //attendo solo SIGUSR1
  sigfillset(&mask);
  sigdelset(&mask,SIGUSR1);
  sigsuspend(&mask);
 
  printf("Padre esce.\n");
  return 0;
}

 

 

13- SOA/esempi utili catalogati/c_ps/2008-01-23.c/*TESTO 2008-01-23
 
Si realizzi un server concorrente su socket STREAM che abbia il seguente comportamento:
 
- il processo server Ps riceve dal client un primo messaggio ?SETUP? e crea un processo figlio Pf che si mette inizialmente in attesa di un segnale;
 
- dopo aver ricevuto dal client un secondo messaggio ?START? il processo server invia un segnale SIGUSR1 a Pf;
 
- dopo aver rispettivamente inviato e ricevuto il segnale SIGUSR1, Ps e Pf devono attendere un intervallo di durata casuale tra 1 e 10 secondi,
  prima di inviare un segnale SIGKILL all?altro processo e terminare;
 
- al processo client dovra' essere trasmesso un messaggio ASCII contenente, sia per Ps che per Pf , il relativo PID e un?indicazione del fatto che abbia inviato o meno
  il segnale SIGKILL.
 
Si richiede l?utilizzo della gestione affidabile dei segnali.
Si suggerisce l?utilizzo del comando telnet come client per la verifica del funzionamento del server
 
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
 
#define PORT1 8080
 
int sock,msgsock,porta;
struct sockaddr_in server;
 
int pidPs, pidPf;
char buffer[256];
struct sockaddr_in client;
int lenght;
 
struct sigaction sig;
 
void handler (int signo)
{
    if(signo == SIGUSR1)
        printf("Processo figlio: sono il processo con PID %d e ho ricevuto il segnale SIGUSR1\n", getpid());
    else
        printf("Segnale non gestito\n");
}
 
 
/*
    NOTA: Per come e' formulato il testo resta sempre la possibilita' di una corsa critica, nel caso in cui entrambi i SIGKILL vengano inviati assieme;
    la conseguenza e' che nessuna delle due write viene eseguita, e al client non arriva nessun messaggio dopo l'invio del comando START
*/
int main()
{
    /*DEFINIZIONE DELLA GESTIONE "AFFIDABILE" DEI SEGNALI*/
    sig.sa_handler = handler; //installo il gestore del segnale SIGUSR1
    sigemptyset(&sig.sa_mask);
    sig.sa_flags=0;
    sigaction(SIGUSR1,&sig,NULL);
 
    pidPs=getpid();
 
    /*DEFINIZIONE DELLA COMUNICAZIONE ATTRAVERSO SOCKET STREAM*/
 
    /*Creo la SOCKET*/
    sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock<0) {
 
        perror("creazione stream socket");
        exit(-1);
    }
 
    /*Preparo la struttura sockaddr_in per settare i parametri della socket con PORT1*/
    server.sin_family=AF_INET;         /*internet protocol*/
    server.sin_addr.s_addr=INADDR_ANY; /*ascolto da tutte le interfacce*/
    server.sin_port=htons(PORT1);       /*e dalla porta specificata*/
 
    if(bind(sock,(struct sockaddr *)&server,sizeof(server)) < 0) {
 
        perror("binding stream socket");
        exit(-1);
    }
 
    /*Stampo il pid del processo server e il nome della porta di comunicazione*/
    printf("Server %d attivo sulla porta %d\n",getpid(),ntohs(server.sin_port));
 
    /*Dichiaro il numero massimo di connessioni*/
    listen(sock, 5);
 
    lenght=sizeof(client);
    msgsock=accept(sock,(struct sockaddr *)&client,(socklen_t *)&lenght); /*Attendo connesione*/
 
    /*Leggo il primo messaggio ricevuto dal clienr*/
    if(read(msgsock,buffer,256)<0) 
        perror("Errore: lettura del messaggio\n");
 
    /*Controllo il messaggio ricevuto dal client*/
    if(!strncmp(buffer, "SETUP", 5)) {
 
        pidPf=fork();
        /*Creo il processo figlio Pf*/
        if(pidPf<0) {
 
            perror("Errore: creazione processo figlio\n");
            exit(-1);
        }
 
        if(pidPf==0) { /*Processo figlio Pf*/
 
            pidPf=getpid();
 
            srand(getpid());/*Inizializzo il generatore di numeri casuali*/
            sigsuspend(&(sig.sa_mask)); /*Rimango in attesa di un segnale valido*/
 
            int sec = rand()%10+1;
            printf("Figlio (%d): dormo %d s\n", getpid(), sec);
            sleep(sec);
            kill(pidPs, SIGKILL); /*Spedisco il segnale SIGKILL al processo server Ps*/
            sprintf(buffer, "Padre (%d): segnale non inviato\nFiglio (%d): segnale inviato\n", pidPs, pidPf);
 
            if(write(msgsock, buffer, strlen(buffer)) < 0) /*Spedisco il messaggio al client*/
                perror("Errore: scrittura del messaggio\n");
 
            exit(0);
        }
    } else {
 
        printf("Errore: comando non corretto %s\n");
        exit(-1);
    }
 
    /*Leggo il secondo messaggio ricevuto dal clienr*/
    if(read(msgsock,buffer,256)<0)
        perror("Errore: lettura del messaggio\n");
 
    /*Controllo il messaggio ricevuto dal client*/
    if(!strncmp(buffer, "START", 5)) {
 
        srand(getpid());/*Inizializzo il generatore di numeri casuali*/
        kill(pidPf, SIGUSR1); /*Spedisco il segnale SIGUSR1 al processo figlio Pf*/
 
        int sec = rand()%10+1;
        printf("Padre (%d): dormo %d s\n", getpid(), sec);
        sleep(sec);
        kill(pidPf, SIGKILL); /*Spedisco il segnale SIGKILL al processo figlio Pf*/
 
        sprintf(buffer, "Padre (%d): segnale inviato\nFiglio (%d): segnale non inviato\n", pidPs, pidPf);
 
        if(write(msgsock, buffer, strlen(buffer)) < 0) /*Spedisco il messaggio al client*/
            perror("Errore: scrittura del messaggio\n");
 
        exit(0);
    } else {
 
        printf("Errore: comando non corretto\n");
        exit(-1);
    }
 
    close(sock);
    close(msgsock);
 
    return 0;
}

 

4.         

14-SOA/esempi utili catalogati/c_ps/2008-02-25.c/*TESTO: 2008-02-25
    Si realizzi un programma in C che abbia il seguente comportamento:
    - il processo genera un figlio
    - il figlio trasmette al padre un numero casuale compreso tra 0 e 50
    - il padre genera un altro numero casuale (sempre tra 0 e 50), lo somma a quello ricevuto, e lo
      rispedisce al figlio visualizzando
      <proprio PID>:        <numero casuale estratto> <somma inviata>
    - il figlio fa la stessa cosa: genera un altro numero casuale (sempre tra 0 e 50), lo somma a quello
      ricevuto, e lo rispedisce al padre visualizzando
      <proprio PID>:        <numero casuale estratto> <somma inviata>
    - lo scambio di messaggi deve procedere finchè il numero da inviare risulta maggiore di 1000. Non
      appena un processo ottiene una somma superiore a 1000, deve inviare un segnale SIGUSR1
      all’altro processo, il quale alla ricezione termina visualizzando il numero di messaggi ricevuti.
    - Dopo aver inviato il segnale SIGUSR1 il processo termina visualizzando il valore finale della
      somma (che sar  superiore a 1000).
 
Si utilizzi la gestione affidabile dei segnali.
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
 
int cont = 0;
 
void handler(int signo)
{
 
    if (signo==SIGUSR1)  {
 
        printf("Sono il processo %d e termino in seguito alla ricezione di un segnale,e ho ricevuto  %d messaggi\n",getpid(),cont);
        exit(0);
    } else
        printf("Segnale non gestito");
}
 
int main()
{
 
    int pidp,pidf;
    int p1[2];
    int p2[2];
    int numerocasuale,somma,numeropadre;
    struct sigaction sig;
 
    printf("Sono il processo padre con pid %d\n",getpid());
    pidp=getpid();
 
    //creazione pipe
    if (pipe(p1)<0)  {
        perror("Pipe error");
        exit(-1);
    }
 
    if (pipe(p2)<0)  {
        perror("Pipe error");
        exit(-1);
    }
 
    //gestione affidabile dei segnali
    sig.sa_handler=handler;
    sigemptyset(&sig.sa_mask);
    sig.sa_flags=0;
    sigaction(SIGUSR1,&sig,NULL);
 
    //il padre crea il processo figlio
    if ((pidf=fork())<0)  {
        perror("Errore di fork");
        exit(-1);
    }
 
    if (pidf==0)  {    //codice figlio
 
        close(p1[0]);
        close(p2[1]);
        srand(getpid());   //inizializzo il generatore di numeri casuali
 
        somma=rand()%50;
        if(write(p1[1],&somma,sizeof(somma))<0) {
 
            perror("Errore di scrittura");
            exit(-1);
        }
 
        do {
 
            if(read(p2[0],&somma,sizeof(somma))<0)  {
 
                perror("Errore in lettura");
                exit(-1);
            }
 
            cont++;
            numerocasuale=rand()%50;
            somma+=numerocasuale;
 
            printf("Pid %d: numero casuale %d  somma inviata %d\n",getpid(),numerocasuale,somma);
 
            if(write(p1[1],&somma,sizeof(somma))<0)  {
 
              perror("Errore in scrittura");
              exit(-1);
            }
 
        } while(somma<=1000);
 
        kill(getppid(),SIGUSR1);
        printf("Sono il processo figlio %d e il valore finale di somma è %d\n",getpid(),somma);
        exit(0);
    } else { //processo padre
 
        close(p1[1]);
        close(p2[0]);
 
        do {
 
            if(read(p1[0],&somma,sizeof(somma))<0)  {
                perror("Errore in lettura");
                exit(-1);
            }
 
            cont++;
            numeropadre=rand()%50;
            somma+=numeropadre;
 
            printf("Pid %d: numero casuale %d  somma inviata %d\n",getpid(),numeropadre,somma);
 
            if(write(p2[1],&somma,sizeof(somma))<0)  {
 
                perror("Errore in scrittura");
                exit(-1);
            }
 
        } while(somma<=1000);
 
        kill(pidf,SIGUSR1);
        printf("Sono il processo padre %d e il valore finale di somma è %d\n",getpid(),somma);
        exit(0);
    }
 
    return 0;
}

 

 

15-SOA/esempi utili catalogati/c_ps/2008-06-19.c#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
 
#define MAX_CHILD 10
 
int n;
int child_pids[MAX_CHILD];
 
void handler(int signo) {              // funzione da eseguire all'arrivo del segnale
 
    int i;
 
    for(i = 0; i < n; ++i) {
 
        printf("killing child process %d\n", child_pids[i]);
        kill(child_pids[i], SIGTERM);
    }
 
    exit(0);
}
 
int main(int argc,char *argv[])
{
    int pid,i,s;
    int sum;
    int pdchf[2];
    int numero;
    int arrivo;
    struct sigaction act;
    sigset_t sigmask, zeromask;
 
    if(argc !=2) {
 
        fprintf(stderr,"Use: %s N\n",argv[0]);
        exit(-1);
    }
 
    n = atoi(argv[1]);
 
    if(n < 1)
        n = 1;
    else if(n > MAX_CHILD)
        n = MAX_CHILD;
 
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags= 0;
    sigaction(SIGUSR1, &act, NULL);
 
    // blocco il segnale SIGUSR1
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGUSR1);
    sigprocmask(SIG_BLOCK, &sigmask, NULL);
 
    // apro la pipe per la comunicazione da padre a figlio
    if (pipe(pdchf) < 0) {
 
        perror("pipe() error");
        exit(1);
    }
 
    /* creo i figli  */
    for(i = 0; i < n ; i++) {
 
        if((pid=fork())<0) {  //controllo che non ci siano errori nel processo di creazione dei figli
 
          perror("fork() error");
          exit(-2);
        } else {
 
            if(pid == 0) { /* Processi figli */
 
                sum = 0;
                close(pdchf[1]);
 
                printf("CHILD %d created\n", getpid());
 
                do {
 
                    read(pdchf[0], &arrivo, sizeof(int));
                    printf("CHILD %d: read %d -> sum  = %d\n", getpid(), arrivo, sum + arrivo);
                    sum += arrivo;
                } while(sum <= 500);
 
                // ho un totale di numeri superiori a 500 quindi invio il segnale al padre
                kill(getppid(), SIGUSR1);
                printf("CHILD %d: sum = %d, sending SIGUSR1...\n",getpid(), sum);
                exit(0);
            } else {
 
                child_pids[i] = pid;
            }
        }
    }
 
    printf("Child process creation complete, starting to write...\n");
 
    close(pdchf[0]); //il padre sulla pipe deve solo scrivere cosa mandare al figlio
    srand(time(0));
 
    for(s = 0; s < 5; s++) {  //lo faccio entrare in un for dove manda 5 numeri e intanto è insensibile a SIGUSR1
 
        sleep(2);
        numero = rand() % 90 + 10;
        printf("sending %d\n", numero);
        write(pdchf[1], &numero, sizeof(int));
    }
 
    printf("Five iterations completed, unmasking SIGUSR1...\n");
 
    sigprocmask(SIG_UNBLOCK, &sigmask, NULL); //ora che ho inviato come minimo 5 segnali il padre diventa sensibile a SIGUSR1
 
 
    for(;;) {
 
        sleep(2);
        numero = rand() % 90 + 10;