codice:
--------SERVER-----
#include <sys/types.h> /* predefined types */
#include <unistd.h> /* include unix standard library */
#include <arpa/inet.h> /* IP addresses conversion utililites */
#include <sys/socket.h> /* socket library */
#include <stdio.h> /* include standard I/O library */
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <netdb.h>
#include <fcntl.h>/*gestione file*/
#define BUFSIZE 1024
#define max(a,b) ((a) > (b) ? (a) : (b))
int visualizza_lista_e_scegli(int conn_fd);
void file_scelto(int conn_fd,int scelta,char *nomefilescelto);
int main (int argc , char *argv[])
{
int list_fd,conn_fd;
int i,scelta;
int fd,nread,maxfd,nwrite,k,size,milisec;
struct sockaddr_in serv_add,client;
char buffer[BUFSIZE],PRONTO[2],nomefilescelto[256];
socklen_t len;
time_t timeval;
pid_t pid;
int logging =1;
struct hostent *rdata;
fd_set rset,wset;
milisec = 10; // Dimensione in millisecondi dello sleep
struct timespec req = {0};
req.tv_sec = 0;
req.tv_nsec = milisec * 1000000L;
// Variabile per contare i byte inviati
size=0;
// Variabile per la gestione di pausa, ripresa e terminazione del client
// Se k=0 --> invio normale
// Se k=1 --> il client ha deciso di mettere in pausa il download
k=0;
//SOCKET
if ( ( list_fd = socket(AF_INET, SOCK_STREAM, 0) ) < 0 )
{
perror("socket");
exit(1);
}
//SIN_FAMILY
serv_add.sin_family = AF_INET;
//SIN_ADDR.S_ADDR
serv_add.sin_addr.s_addr = htonl(INADDR_ANY);
//SIN_PORT
serv_add.sin_port = htons(1121);
//BIND
if ( bind(list_fd, (struct sockaddr *) &serv_add,sizeof(serv_add)) < 0 )
{
perror("bind");
exit(1);
}
//LISTEN
if ( listen(list_fd, 1024) < 0 )
{
perror("listen");
exit(1);
}
/* write daytime to client */
while(1)
{
len = sizeof ( client );
if ( ( conn_fd = accept(list_fd, (struct sockaddr *) &client, &len) ) < 0 )
{
perror("accept");
exit(1);
}
/* fork per gestire il collegamento */
if((pid= fork())<0)
{
perror (" fork error ");
exit ( -1);
}
if(pid==0)
{ /* figlio*/
timeval = time ( NULL );
/*Menu di Benvenuto*/
snprintf(buffer,sizeof(buffer)," %.24s\r\n-------------------------------\nWelcome to streaming service, scegliere file desiderato.\nPer terminare premere il numero intero '0'.\nATTENZIONE:un carattere qualsiasi o un numero piu grande terminerà il servizio!\n-------------------------------\n",ctime(& timeval));
if((write(conn_fd,buffer,strlen(buffer)))<0)
{
perror (" write error ");
exit ( -1);
}
if(logging)
{
rdata=gethostbyaddr((const char *)&client.sin_addr,sizeof(client.sin_addr),client.sin_family);
if (rdata == NULL)
{
herror("Errore di risoluzione");
exit(1);
}
printf("\n@Request from host %s, port %d\n%.24s\r\n",rdata->h_name,serv_add.sin_port,ctime(& timeval));
}
scelta=visualizza_lista_e_scegli(conn_fd);
if (scelta==0){
printf("\nIl tasto scelto ha terminato il servizio streaming.\n\n-------------------------------\n");
sleep(2);
close(conn_fd);
exit(0);
}
memset(buffer,0,BUFSIZE);
file_scelto(conn_fd,scelta,buffer);
printf("invio file...\n");
fd = open(buffer, O_RDONLY);//Apro il file in lettura
if (fd < 0) {
perror(" open error ");
exit(1);
}
FD_ZERO(&rset);
FD_ZERO(&wset);
maxfd=max(conn_fd, list_fd)+1;
while(1){
/* Se k=0 allora possiamo settare il descrittore del socket
in quanto non ci sono interruzioni da parte del client
e il trasferimento avviene normalmente */
if(k==0)
FD_SET(list_fd,&wset);
FD_SET(conn_fd,&rset);
if (select(maxfd, &rset, &wset, NULL, NULL)<0){
perror(" select error ");
exit(1);
}
/* Usciti dalla select controlliamo se ci sono messaggi per la pausa,
ripresa o terminazione sul socket */
if(FD_ISSET(conn_fd,&rset)){
memset (buffer, 0, sizeof(buffer));
if (read(conn_fd, buffer, BUFSIZE)<0)
{
perror (" read error ");
exit (-1);
}
/* Dal socket leggiamo una 'P' che sta ad indicare una pausa da parte
del client. Quindi 'puliamo' il descrittore del socket, settiamo k=1
e in tal modo mettiamo in pausa il trasferimento dati */
if(buffer[0]=='P'){
FD_CLR(conn_fd,&wset);
k=1;
printf("\nCLIENT on PORT %d ha messo in PAUSA il download.",serv_add.sin_port);
}
/* Dal socket leggiamo una 'R' che sta ad indicare la volonta'
del client di riprendere il download. Quindi settiamo k=0 per
'riattivare' il descrittore del socket e riprendiamo il trasferimento */
if(buffer[0]=='R'){
k=0;
printf("\n\nCLIENT on PORT %d ha RIPRESO il download.",serv_add.sin_port);
printf("\nDownloading...\n");
}
/* Dal socket leggiamo una 'S'. Il client vuole terminare senza aver completato il
download. Quindi chiudiamo la connessione ed usciamo dal server figlio
che gestiva il client */
if(buffer[0]=='S'){
printf("\n\nCLIENT on PORT %d ha TERMINATO FORZATAMENTE il download.",serv_add.sin_port);
printf("\nConnessione con CLIENT chiusa.\n\n");
sleep(2);
close(conn_fd);
exit(0);
}
fflush(stdout);
}
/* Controlliamo se ci sono ancora dati da scrivere sul socket */
if(FD_ISSET(list_fd,&wset)){
// 'Addormentiamo' il processo per pochi millisecondi
nanosleep(&req, (struct timespec *)NULL);
/* Controlliamo se dal file aperto in lettura ci sono ancora da leggere dei byte*/
if((nread=read(fd,buffer,1024))<0)
{
perror (" read error ");
exit (-1);
}
/* Li spediamo */
if ((nwrite=sendto(conn_fd, buffer, nread, 0, (struct sockaddr *)&serv_add, len))<0){
perror(" sendto error");
exit(-1);
}
size+=nwrite;
/* Se non ci sono piu' byte da leggere dal file allora significa
che il trasferimento e' andato a buon fine. Quindi chiudiamo il
socket ed usciamo dal server figlio.*/
if(nread==0){
printf("\n\nFile inviato correttamente : \n%d byte al CLIENT on PORT %d.\n\n",size,serv_add.sin_port);
close(conn_fd);
exit(0);
}
}
}//While
}//pid
else
{ /* padre */
close (conn_fd);
}
}
/* normal exit , never reached */
exit (0);
}
int visualizza_lista_e_scegli(int conn_fd)
{
int scelta, fileDim = 0;
char *buffer;
FILE *file;
char ch, FileName[256]="streaming.txt";
if(( file = fopen( FileName, "r")) != NULL)
{
// Si posiziona alla fine del file
fseek(file, 0, SEEK_END);
// Legge la posizione attuale
fileDim = ftell(file);
// Alloca la dimensione del buffer
buffer = (char*) malloc(sizeof(char) * fileDim+1);
printf("\nDimensione del file %s = %d\n", FileName, fileDim);
// Mi riporto all'inizio del file
fseek(file, 0, SEEK_SET);
// Copio tutto il contenuto del file nel buffer
fread(buffer, fileDim, 1, file);
// Chiudo il file
fclose(file);
}
//inviamo l'elenco al client
if(write(conn_fd,buffer,strlen(buffer)+1)<0)
{
perror (" write error ");
exit ( -1);
}
/*leggiamo la scelta del client*/
if(read(conn_fd,&scelta,sizeof(scelta))<0)
{
perror (" read error ");
exit ( -1);
}
return (scelta);
}
void file_scelto(int conn_fd, int scelta, char *buffer)
{
FILE *file;
char FileName[256]="streaming.txt";
char a[256];
int i=0;
if(( file = fopen( FileName, "r")) != NULL)
{
//finchè non è finito il file
while(!feof(file))
{
//incrementiamo "i" in modo tale da far combaciare l'array che parte da zero con la lista che parte da uno
i++;
//leggiamo streaming.txt per righe e lo inseriamo nell'array di stringhe
fgets(a,256,file);
//quando arriviamo alla scelta del client stampiamo il nome del file desiderato dal client
if(i==scelta)
{
strcpy(buffer,a);
printf("\nè stato scelto il seguente file:\n%s",buffer);
//inviamo il nome del file scelto
if(write(conn_fd,buffer,BUFSIZE)<0)
{
perror (" write error ");
exit ( -1);
}
}
}
//se la scelta del client è superiore alla lunghezza per righe della lista mandiamo un messaggio d'errore e chiudiamo la connessione
if ((scelta)>i){
snprintf(buffer,sizeof(buffer),"ERRORE: il numero premuto è troppo grande per la scelta!\n\nIl tasto scelto ha terminato il servizio streaming.\n\n-------------------------------\n");
if (write(conn_fd,buffer,strlen(buffer))<0)
{
perror (" write error ");
exit ( -1);
}
printf("ERRORE: il numero premuto è troppo grande per la scelta!\n\nIl tasto scelto ha terminato il servizio streaming.\n\n-------------------------------");
sleep(2);
close(conn_fd);
exit(0);
}
}
fclose(file);
}