1. Reti di calcolatori - Fabiano Dalla Piazza
===================================================================================
===============================================================
/*SERVER*/
/*TESINA SCRITTA IN C PER RETI DI CALCOLATORI A CURA DI FABIANO DALLA PIAZZA*/
/*UNIVERSITA' DEGLI STUDI DI TRIESTE*/
/*QUESTO FILE E' COMPOSTO DI UN PROGRAMMA PRINCIPALE(main),UNA PROCEDURA(ls) E*/
/*TRE SOTTOPROGRAMMI(invia,ricevi E fai).IL MAIN CREA UN SOCKET,EFFETTUA IL BINDING*/
/*TRA SOCKET E INDIRIZZO DELLA MACCHINA LOCALE,OTTIENE IL NOME DEL SOCKET ED
ESEGUE*/
/*IL LISTENING PER COMUNICARE LA DISPONIBILTA' AD ACCETTARE FINO A 8 CONNESSIONI.*/
/*POI,SE RIESCE A IMPOSTARE LA MODALITA' PASSIVA,ELABORA LE RICHIESTE DEL CLIENT*/
/*AVVALENDOSI DEL SOTTOPROGRAMMA FAI E CHIUDE LA CONNESSIONE TCP SIA IN INPUT,SIA IN
OUTPUT.*/
/*IL SOTTOPROGRAMMA FAI PRENDE LA PRIMA RICHIESTA IN CODA E CREA UN ALTRO SOCKET.*/
/*LEGGE I PARAMETRI E IL COMANDO INVIATOGLI DAL CLIENT TRAMITE IL SOTTOPROGRAMMA
RICEVI.*/
/*CONTROLLA LE DIRETTIVE IMPARTITE DAL CLIENT E,SE DEVE USCIRE O TESTARE,CHIAMA IL*/
/*SOTTOPROGRAMMA INVIO PER SEGNALARE IL NUMERO DI RIGHE CHE SI TRASMETTERANNO NEL
CANALE,*/
/*MENTRE SE DEVE ESEGUIRE IL COMANDO LS CHIAMA LA PROCEDURA LS.INFINE CHIUDE IL
SOCKET.*/
/*LA PROCEDURA LS SI INCARICA DI APRIRE LA DIRECTORY,COMUNICARE AL CLIENT L'ARRIVO*/
/*DI RIGHE CON IL SOTTOPROGRAMMA INVIA,ESEGUIRE UN CICLO DI LETTURA,CHIUDERE LA*/
/*DIRECTORY E SEGNALARE IL FINE FLUSSO.*/
/*IL SOTTOPROGRAMMA INVIA FRAMMENTA LA STRINGA RICEVUTA IN FRAMES E LI INVIA AL
SOCKET,MENTRE*/
/*IL SOTTOPROGRAMMA RICEVI LEGGE LA STRINGA RICEVUTA E LA IMMETTE NEL BUFFER.*/
/*direttive di definizione al preprocessore*/
/*portad è la porta per default,buffersiz è la capacità di memoria residente nel buffer*/
/*poi ci sono le varie librerie*/
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#ifndef unix
#define WIN32
#include <windows.h>
#include <winsock.h>
#else
#define closesocket close
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#endif
1agina p
2. Reti di calcolatori - Fabiano Dalla Piazza
#if defined __CYGWIN__
#include <io.h>
#else
#include <sys/io.h>
#endif
#define portad 5193
#define buffersiz 500
/*prototipi dei sottoprogrammi e procedure varie*/
int invia(int sid,char *str);
int ricevi(int sid,char *str,int siz);
int fai(int soce);
void ls(int scke,char *wher);
/*programma principale*/
int main(int argc,char *argv[]){
int skt,lun,por,warn,ext;
struct sockaddr_in skaddr;
ext=0;
warn=1;
/*la porta é quella di default*/
por=portad;
/*confronto i parametri in ingresso*/
if(argc > 1){
/*se é l'help,visualizzo l'aiuto*/
if(strcmp(argv[1],"--help") == 0)
{
printf("server in uso n");
printf("server la porta del socket diviene quella di default (%i)n",portad);
printf("server[sys] la porta del socket è distribuita dal sistema operativon");
printf("server --help aiutonn");
ext=1;
}
/*se la stringa é sys,il numero di porta é assegnato dal sistema operativo*/
else if(strcmp(argv[1],"sys") == 0)
por=0;
else
{
printf("visualizzare l'aiuton");
2agina p
3. Reti di calcolatori - Fabiano Dalla Piazza
ext=1;
}
}
/*se parametri ok allora*/
if(!ext)
{
/*inizializzazione per WIN32*/
#ifdef WIN32
WSADATA wsaData;
WSAStartup(0x0101,&wsaData);
#endif
/*creazione del socket di famiglia PF_INET,con servizio SOCK_STREAM,tipo TCP(0)*/
/*si crea un protocollo per ciascuna connessione*/
/*se riesco a creare il socket,configuro il suo indirizzo*/
if((skt=socket(PF_INET,SOCK_STREAM,0)) >= 0 && (!ext)){
/*la famiglia dell'indirizzo é AF_INET*/
skaddr.sin_family=AF_INET;
/*l'indirizzo IP locale é INADDR_ANY,uno qualsiasi degli indirizzi IP*/
/*con cui la macchina viene riconosciuta in rete*/
skaddr.sin_addr.s_addr=INADDR_ANY;
/*viene assegnata la porta*/
skaddr.sin_port=htons(por);
/*eseguo il binding(assegnazione nome) tra socket e indirizzo della macchina locale*/
if(bind(skt,(struct sockaddr *) &skaddr,sizeof(skaddr)) >= 0){
/*binding riuscito:allora trovo il numero di porta e lo visualizzo*/
lun=sizeof(skaddr);
/*se ottengo il nome del socket*/
if(getsockname(skt,(struct sockaddr *) &skaddr,&lun) >= 0){
printf("server(locale):il numero della porta e' %dn",ntohs(skaddr.sin_port));
/*il server comunica che é disposto ad accettare connessioni accodate*/
/*fino a un massimo di 8 richieste(numero da
me fissato)*/
if(listen(skt,8) >= 0){
/*se riesco a far lavorare il socket in modalità passiva*/
3agina p
4. Reti di calcolatori - Fabiano Dalla Piazza
if((warn=fai(skt)) != 0)
printf("server(locale):errore di elaborazionen");
/*chiusura della connessione TCP di client e
server(direzione 2)*/
/*se la direzione é 0 chiude solo il server*/
/*se é 1 chiude solo il client*/
shutdown(skt,2);
printf("server(locale):fine operazioni come richiesto dal clientn");
}
else
printf("server(locale):errore nel listenn");
}
else
printf("server(locale):errore nella ricerca nome socketn");
}
else
printf("server(locale):errore nel binding tra socket e macchinan");
}
else
printf("server(locale):errore nella creazione del socketn");
}
return warn;
}
/*implementazione del sottoprogramma fai*/
/*il sottoprogramma esegue le direttive impartite dal client*/
int fai(int soce){
int sonum,abc,k,luind,numerop,erro,ext;
struct sockaddr vie;
char buffe[buffersiz],ord[buffersiz],prmt[3][buffersiz];/*matrice prmt*/
/*con massimo
tre parametri*/
/*ciclo di processo delle richieste del client*/
abc=0;
ext=0;
4agina p
5. Reti di calcolatori - Fabiano Dalla Piazza
erro=0;
for(;!erro && !ext;){
/*fisso una lunghezza di indirizzo pari a 16*/
luind=16;
/*la accept prende la prima richiesta in coda,crea un altro socket(sonum),se */
/*non ci sono richieste in sospeso,si blocca in attesa*/
if((sonum=accept(soce,&vie,&luind)) >= 0)
{
printf("server(locale):c' é una connessione (n.%u),elaboro n",abc);
/*leggo quanti parametri invia il client*/
ricevi(sonum,ord,buffersiz);
/*converto in intero e visualizzo numero parametri*/
numerop=atoi(ord);
printf("numero parametri= %un",numerop);
/*leggo il comando del client*/
ricevi(sonum,ord,buffersiz);
/*controllo del comando del client*/
if(strcmp(ord,"ls") == 0 || strcmp(ord,"exit") == 0 || strcmp(ord,"test") == 0){
/*comando valido,allora considero il comando ricevuto*/
if(strcmp(ord,"exit") == 0){
/*richiesta di fine elaborazione*/
ext=1;
/*invio il numero di righe che si trasmetteranno nel canale*/
invia(sonum,"2");
invia(sonum,"sono il server:fine elaborazioni ");
}
else{
/*se il comando non é exit,azzero i vecchi parametri*/
/*e leggo gli eventuali parametri rimanenti*/
/*ciclo fino a tre perché é l numero massimo di parametri
che consento*/
for(k=0;k < 3;k++)
prmt[k][0]='0';
for(k=0;k < numerop-1;k++){
5agina p
6. Reti di calcolatori - Fabiano Dalla Piazza
ricevi(sonum,buffe,buffersiz);
if(k < 3)
/*salvo il comando,(3) é sempre il max numero parametri*/
strcpy(prmt[k],buffe);
}
if(strcmp(ord,"test") == 0){
/*se il comando é test*/
invia(sonum,"2");
invia(sonum,"sono il server:eseguo il test ");
}
else{
/*caso in cui il comando é ls:il client cercherà
nella directory*/
/*se la stringa é zero,non viene specificata una
directory*/
/*su cui eseguire il listing*/
if(strcmp(prmt[0],"") == 0)
ls(sonum,"");
else
ls(sonum,"r");
}
}
}
else{
/*comando non valido*/
/*invio il numero di righe che si trasmetteranno nel canale*/
invia(sonum,"2");
invia(sonum,"comando non valido ");
/*tolgo eventuali parametri passati nel canale*/
for(k=0;k < numerop-1;k++)
ricevi(sonum,buffe,buffersiz);
}
printf("server(locale):connessione elaborata (n.%u)n",abc);
/*chiusura del socket di comunicazione*/
closesocket(sock);
abc++;
}
else
erro= 1;
6agina p
7. Reti di calcolatori - Fabiano Dalla Piazza
}
return erro;
}
/*procedura ls*/
void ls(int scke,char *wher){
int errore;
DIR *direc=NULL;
struct dirent *afd=NULL;
char nmfl[24];/*massimo numero caratteri del nome file fissato a 24*/
errore=1;
/*se non viene specificata una directory*/
if(*wher == '0')
/*allora apro la directory locale del server*/
direc=opendir(".");
/*altrimenti apro quella specificata per il listing*/
else
direc=opendir(wher);
/*se la directory non é vuota*/
if(direc != NULL){
/*avviso il client dell'arrivo di un numero imprecisato di righe*/
invia(scke,"0");
/*ciclo di lettura dei files*/
while(!errore && (afd=readdir(direc))!=NULL){
/*terminatore di stringa*/
#ifndef _DIRENT_HAVE_D_NAMLEN
strncpy(nmfl,afd->d_name,afd->d_namlen+1);
#else
strcpy(nmfl,afd->d_name);
#endif
/*invio stringa al client*/
invia(scke,nmfl);
}
/*chiudo la directory*/
closedir(direc);
/*avverto il client del termine flusso*/
if(!errore)
7agina p
8. Reti di calcolatori - Fabiano Dalla Piazza
invia(scke,"FINEFLUSSO");
}
else{
/*errore nel parametro,avvertimento al client*/
invia(sd,"2");
invia(sd,"errore nel parametro ls");
}
}
/*il sottoprogramma invia manda pezzi di stringa al socket*/
/*in base ai dati forniti,e aggiunge un terminatore di fine stringa newline*/
int invia(int sid,char *str){
int dim,scr,siz,a,wri,exi;
char newl[2];
/*trovo la lunghezza stringa e azzero i parametri contatore e uscita*/
siz=dim=strlen(str);
a=0;
exi=0;
/*finché c'è stringa e non esco,invio un suo pezzo,*/
/*ricordo dove sono arrivato e scalo dal contatore*/
while(siz > 0 && (!exi)){
/*invio vero e proprio*/
wri=send(sid,str+a,siz,0);
if(wri > 0){
a+=wri;
siz-=wri;
}
/*errore in trasmissione:esco*/
else
exi=1;
}
/*lunghezza stringa rimanente*/
scr=(strlen(str)-siz);
/*aggiungo il carattere newline come terminatore di fine stringa*/
strcpy(newl,"n");
if(dim > 0 && str[dim-1]!='n'){
siz=strlen(newl);
a=0;
8agina p
9. Reti di calcolatori - Fabiano Dalla Piazza
exi=0;
while(siz > 0 && (!exi)){
wri=send(sid,newl+a,siz,0);
/*errore,esco*/
if(wri <= 0)
exi=1;
else{
a+=wri;
siz-=wri;
}
}
scr=(strlen(newl)-siz);
}
/*restiruisco la lunghezza stringa rimanente*/
return scr;
}
/*il sottoprogramma ricevi legge un byte alla volta la stringa del socket sid,*/
/*la inserisce nel buffer,terminandola con null(come negli esempi),infine*/
/*restituisce il numero di caratteri della stringa*/
int ricevi(int sid,char *str,int siz){
int a,rea,exi;
char c;
a=0;
exi=0;
/*finché non devo uscire,eseguo un ciclo di lettura dal socket*/
/*un carattere alla volta*/
for(;!exi;){
rea=recv(sid,&c,1,0);
/*caso standard:c'é il carattere e non é newline*/
if(rea == 1 && a < siz && c!='n'){
*(str+a)=c;
a++;
}
/*se non ho carattere o esso é newline,esco*/
else if((rea == 0)||(rea == 1 && c == 'n')){
*(str+a)='0';
rea=a+1;
exi=1;
}
/*in caso di errore,esco*/
else{
*(str+a)='0';
rea=-1;
9agina p
10. Reti di calcolatori - Fabiano Dalla Piazza
exi=1;
}
}
/*restituisco il numero di caratteri eccetto il terminatore*/
return rea;
}
===================================================================================
===============================================================
/*CLIENT*/
/*TESINA SCRITTA IN C PER RETI DI CALCOLATORI A CURA DI FABIANO DALLA PIAZZA*/
/*UNIVERSITA' DEGLI STUDI DI TRIESTE*/
/*IL FILE E' COMPOSTO DAL PROGRAMMA PRINCIPALE(main) E DUE SOTTOPROGRAMMI(invia e
ricevi).*/
/*IL MAIN CREA UN SOCKET IP ORIENTATO ALLA CONNESSIONE TCP DI DOMINIO
INTERNET,GUARDA NELLA DNS E*/
/*OTTIENE IL NOME DELL'HOST SERVER.EFFETTUA LA CONNESSIONE,USA IL SOTTOPROGRAMMA
INVIA PER MANDARE*/
/*AL SOCKET I PARAMETRI E IL COMANDO DA ESEGUIRE.USA IL SOTTOPROGRAMMA RICEVI PER
SAPERE*/
/*QUANTI PARAMETRI RICEVERA' DALL'UTENTE,E IN BASE A CIO' SA QUANTE RIGHE SUCCESSIVE
ATTENDERSI,*/
/*LE LEGGE CON IL SOTTOPROGRAMMA RICEVI,EVENTUALMENTE RICEVENDO UNA STRINGA DI
"FINEFLUSSO"*/
/*QUALORA IL NUMERO DI RIGHE NON SIA NOTO A PRIORI.INFINE CHIUDE IL SOCKET.*/
/*IL SOTTOPROGRAMMA INVIA FRAMMENTA LA STRINGA RICEVUTA IN FRAMES E LI INVIA AL
SOCKET,MENTRE*/
/*IL SOTTOPROGRAMMA RICEVI LEGGE LA STRINGA RICEVUTA E LA IMMETTE NEL BUFFER.*/
/*direttive di definizione al preprocessore*/
/*portad è la porta per default,buffersiz è la capacità di memoria residente nel buffer*/
/*poi ci sono le varie librerie*/
#include <stdio.h>
#include <string.h>
#ifndef unix
#define WIN32
#include <windows.h>
#include <winsock.h>
#else
#define closesocket close
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
10agina p
11. Reti di calcolatori - Fabiano Dalla Piazza
#include <netdb.h>
#endif
#define portad 5193
#define buffersiz 500
/*prototipi delle funzioni di lettura e spedizione dati*/
/*sid é l'astrazione per la comunicazione di rete*/
int invia(int sid,char *str);
int ricevi(int sid,char *str,int siz);
/*corpo del programma*/
int main(int argc,char *argv[]){
int j,sock,numerop,uscita;
struct hostent *hpt;
struct sockaddr_in skaddr;
char buff[buffersiz];
/*inizializzazione per WIN32*/
#ifdef WIN32
WSADATA wsaData;
WSAStartup(0x0101,&wsaData);
#endif
if(argc < 4){
/*se non ho parametri a sufficienza*/
printf("client n");
printf("client <host_server> <porta> <exit> termina la connessionen");
printf("client <host_server> <porta> <ls> [file [">" file2]] directory remotan");
printf("client <host_server> <porta> <test> test della connessionen");
printf("nse la <porta> == default (allora la porta diviene quella di default
(%i)nn",portad);
}
else{
/*se ho parametri sufficienti*/
uscita=0;
/*creo un socket IP orientato alla connessione TCP*/
/*di dominio Internet PF_INET e tipo,protocollo SOCK_STREAM,0*/
if((sock=socket(PF_INET,SOCK_STREAM,0)) >= 0 && (!uscita)){
/*se creo il socket e non devo uscire*/
if((hpt= gethostbyname(argv[1])) != 0){
11agina p
12. Reti di calcolatori - Fabiano Dalla Piazza
/*con la funzione gethostbyname ottengo il nome dell'host:guarda*/
/*nella DNS e ritorna il puntatore *hpt alla struttura*/
/*configurazione della struttura con famiglia di indirizzi AF_INET*/
/*per indirizzi TCP/IP,e mappa il nome di protocollo*/
/*di trasporto al numero di protocollo*/
skaddr.sin_family= AF_INET;
memcpy(&skaddr.sin_addr.s_addr,hpt->h_addr,hpt->h_length);
if(strcmp(argv[2],"def") == 0)
/*confronto le due stringhe:se sono uguali uso la porta di default*/
skaddr.sin_port=htons(portad);
else
/*altrimenti se le due stringhe non sono uguali non uso*/
/*la porta di default*/
skaddr.sin_port=htons(atoi(argv[2]));
/*connetto il server con connect*/
if(connect(sock,(struct sockaddr *) &skaddr,sizeof(skaddr)) >= 0){
/*invio il numero dei parametri,poi primo
parametro,secondo parametro,etc..*/ /*sprintf invia l'output nel
buffer*/
sprintf(buff,"%i",argc - 3);
/*vengono inviati i parametri forniti dall'utente*/
invia(sock,buff);
/*viene inviato il comando*/
invia(sock,argv[3]);
/*se esistono altri parametri,invio anche quelli*/
for(j=4;j < argc;j++)
invia(sock,argv[j]);
/*leggo un byte alla volta dalla prima stringa del socket
sock*/
/*quanti parametri riceverò e la inserisco nel buffer*/
ricevi(sock,buff,buffersiz);
/*converto in intero*/
numerop=atoi(buff);
/*se il numero di parametri è nullo,allora il*/
/*numero righe é imprecisato*/
12agina p
13. Reti di calcolatori - Fabiano Dalla Piazza
if(numerop == 0){
/*risposta del server*/
printf("client:la risposta dal server é:n");
uscita=0;
/*se non esco*/
for(;!uscita;){
/*leggo un byte alla volta la stringa
del socket sock*/
/*e la inserisco nel buffer*/
ricevi(sock,buff,buffersiz);
/*se la stringa ricevuta è
FINEFLUSSO esco*/
/*dal ciclo:non ci sono più stringhe
da leggere*/
if(strcmp(buff,"FINEFLUSSO")==0)
uscita= 1;
else
printf("%sn",buff);
}
}
else{
/*se il numero di righe non è zero*/
/*ci saranno numero di parametri-1 riga*/
printf("client:la risposta dal server é:n",numerop-1);
/*cicla numero righe-1 volte*/
for (j=0;j < numerop-1;j++){
/*leggo un byte alla volta la stringa
del socket sock*/
/*e la inserisco nel buffer*/
ricevi(sock,buff,buffersiz);
/*visualizzo*/
printf("%sn",buff);
}
}
}
13agina p
14. Reti di calcolatori - Fabiano Dalla Piazza
else
/*se la connessione non riesce*/
printf("client:connessione col server non riuscita!n");
}
else
/*host sconosciuto o quantomeno indeterminabile*/
printf("client:errore hostn");
/*chiusura del socket di comunicazione*/
closesocket(sock);
}
else
printf("client:creazione socket non valida!n");
}
return 0;
}
/*il sottoprogramma invia manda pezzi di stringa al socket*/
/*in base ai dati forniti,e aggiunge un terminatore di fine stringa newline*/
int invia(int sid,char *str){
int dim,scr,siz,a,wri,exi;
char newl[2];
/*trovo la lunghezza stringa e azzero i parametri contatore e uscita*/
siz=dim=strlen(str);
a=0;
exi=0;
/*finché c'è stringa e non esco,invio un suo pezzo,*/
/*ricordo dove sono arrivato e scalo dal contatore*/
while(siz > 0 && (!exi)){
/*invio vero e proprio*/
wri=send(sid,str+a,siz,0);
if(wri > 0){
a+=wri;
siz-=wri;
}
/*errore in trasmissione:esco*/
else
exi=1;
14agina p
15. Reti di calcolatori - Fabiano Dalla Piazza
}
/*lunghezza stringa rimanente*/
scr=(strlen(str)-siz);
/*aggiungo il carattere newline come terminatore di fine stringa*/
strcpy(newl,"n");
if(dim > 0 && str[dim-1]!='n'){
siz=strlen(newl);
a=0;
exi=0;
while(siz > 0 && (!exi)){
wri=send(sid,newl+a,siz,0);
/*errore,esco*/
if(wri <= 0)
exi=1;
else{
a+=wri;
siz-=wri;
}
}
scr=(strlen(newl)-siz);
}
/*restiruisco la lunghezza stringa rimanente*/
return scr;
}
/*il sottoprogramma ricevi legge un byte alla volta la stringa del socket sid,*/
/*la inserisce nel buffer,terminandola con null(come negli esempi),infine*/
/*restituisce il numero di caratteri della stringa*/
int ricevi(int sid,char *str,int siz){
int a,rea,exi;
char c;
a=0;
exi=0;
/*finché non devo uscire,eseguo un ciclo di lettura dal socket*/
/*un carattere alla volta*/
for(;!exi;){
rea=recv(sid,&c,1,0);
/*caso standard:c'é il carattere e non é newline*/
if(rea == 1 && a < siz && c!='n'){
*(str+a)=c;
a++;
}
15agina p
16. Reti di calcolatori - Fabiano Dalla Piazza
/*se non ho carattere o esso é newline,esco*/
else if((rea == 0)||(rea == 1 && c == 'n')){
*(str+a)='0';
rea=a+1;
exi=1;
}
/*in caso di errore,esco*/
else{
*(str+a)='0';
rea=-1;
exi=1;
}
}
/*restituisco il numero di caratteri eccetto il terminatore*/
return rea;
}
===================================================================================
===============================================================
16agina p