Pagina 1 di 1

[C]Problema poll client - server

Inviato: venerdì 30 marzo 2018, 12:34
da DeN96
Ciao a tutti, sto scrivendo un client - server, in c, che ha lo scopo di implementare una chat.
La comunicazione tra client e server avviene tramite socket di tipo AF_UNIX.

In breve: ho un processo che simula il client che richiede operazioni al server che, se legali, le esegue.
Il server è strutturato con:
- un main che esegue la parte di inizializzazione e che nel ciclo while principale esegue la poll e mette in coda i file descriptor che vogliono comunicare;
- un thread listener che esegue in un while la funzione accept
- dei thread worker che prelevano le richieste dalla coda (la stessa del main) e eseguono le operazioni richieste.

Durante l'esecuzione ho un problema e non riesco a capire da che cosa è dovuto.
La fase di inizializzazione avviene quasi correttamente. Dico quasi perchè il path di dove avviene la creazione del socket mi da qualche problema.
Lato server eseguo il parsing di un file di configurazione da cui estraggo alcune informazioni come il path. Esso ha lunghezza 20 ma la funzione sizeof mi restituisce come dimensione 8.
Lato client passo il path direttamente al main ma anche in esso la funzione sizeof mi restituisce 8 e non 20.
Al momento ho deciso, quindi, di troncare il path a 8 caratteri.

Tuttavia il problema più grande ce l'ho nel main e in particolare nella funzione poll.
il client funziona correttamente e crea la connessione con questa funzione:

Codice: Seleziona tutto

int openConnection(char* path, unsigned int ntimes, unsigned int secs){
    int fd_clt=-1, i;
    //alloco e riempio la struttura per l'indirizzo
    struct sockaddr_un sa;
    strncpy(sa.sun_path, path, sizeof(path));
    sa.sun_family=AF_UNIX;
    if((fd_clt=socket(AF_UNIX, SOCK_STREAM, 0))==-1){
	perror("socket");
	return -1;
    }
    //provo a connettermi
    for(i=0;i<ntimes;i++){
	if((connect(fd_clt, (struct sockaddr*)&sa, sizeof(sa)))==-1){
	    perror("connect");
	    sleep(secs);
	}
	else{
	    return fd_clt;
	}
    }
return -1;
}
Il primo client fd_clt = 3 ma il thread listener bloccato sulla accept mi restituisce 4
Per provare a farlo funzionare ho decrementato nel server questo fd così che concida con quello del client (Non so se sia giusto farlo ma mi da errore se gli fd sono diversi).
Il client viene messo nel set della poll dal thread listener e poi dal main dovrei essere notificato quando il client scrive qualcosa.
Il problema è proprio questo, che non vengo notificato! Sono sicuro che il client scriva qualcosa sul socket ma nonostante ciò la poll mi restituisce sempre 0. Allego le parti di codice principali del main e del listener. Ringrazio chiunque mi voglia aiutare

LISTENER:

Codice: Seleziona tutto

static void *listener(void *arg){
    int new_fd=0, count_err=0, trovato=0, i=0, err=0, temp=0;
    printf("Sono il listener\n");
    //while in cui eseguo l'accept e controllo gli eventuali errori
    while (kill_all==0){
	printf("LISTENER: Inizio ciclo while\n");
	if((new_fd=accept(fd_skt, NULL, 0))==-1){
	    printf("LISTENER: ERRORE accept\n");
	    temp=errno;
	    switch(temp){
		case EWOULDBLOCK: {   //socket impostato come non bloccante e nessuna connessione è in attesa di essere accettata
		    count_err=0;
		} break;
		default:{
		    fprintf(stderr,"Errore nella funzione accept; Funzione listener\n");
		    perror("accept");
		    if(count_err>3){  //non termino subito se è presente un errore ma solo se ce ne sono 3 consecutivi
		        exit(EXIT_FAILURE);
		    }
		    else{
			count_err++;
			//aggiorno le statistiche:errori++
			if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
			    fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
		    }
		}break;
	    }
	}
	else{
	    printf("LISTENER: accept terminata, fd=%d\n",new_fd);
	    count_err=0;
	    //inserisco il nuovo fd nella poll
	    trovato=i=0;
	    if((err=pthread_mutex_lock(&mux_poll))!=0){
		errno=err;
		fprintf(stderr,"Errore nel prendere la lock; Funzione listener; Struttura poll\n");
		perror("lock");
		//aggiorno le statistiche:errori++
		if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
		    fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
		exit(EXIT_FAILURE);
	    }
	    while((i<size_poll) && (trovato==0)){
		if(poll_set[i].fd==-1){
		    poll_set[i].fd=(new_fd-1); 
		    trovato=1;
		    if((modify_pollusers_number(1))!=0){  //incremento il valore degli utenti del set della poll
			fprintf(stderr,"Errore nel decrementare il numero di utenti della poll; Funzione main\n");
			//aggiorno le statistiche:errori++
			if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
			    fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
			exit(EXIT_FAILURE);
		    }
		    if((modify_users_number(1))!=0){  //incremento il valore degli utenti totali
			fprintf(stderr,"Errore nel decrementare il numero di utenti totali; Funzione main\n");
			//aggiorno le statistiche:errori++
			if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
			    fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
			exit(EXIT_FAILURE);
		    }
		}
		else 
		    i++;
	    }
	    if((err=pthread_mutex_unlock(&mux_poll))!=0){
		errno=err;
		fprintf(stderr,"Errore nel rilasciare la lock; Funzione listener; Struttura poll\n");
		perror("unlock");
		//aggiorno le statistiche:errori++
		if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
		    fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
		exit(EXIT_FAILURE);
	    }
	    printf("LISTENER: inserito il client alla posizione i=%d\n", i);
	}
	printf("LISTENER: finito ciclo while\n");
    }
    exit(EXIT_SUCCESS);
}


MAIN:

Codice: Seleziona tutto

//while principale in cui controllo il risultato della poll
    int ret=0, count=0, count_err=0, local_fd=0;
    while(kill_all==0){
	if((err=pthread_mutex_lock(&mux_poll))!=0){
	    errno=err;
	    fprintf(stderr, "Errore nel prendere la lock; Funzione main; Struttura poll\n");
	    perror("lock");
	    //aggiorno le statistiche:errori++
	    if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
		fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
	    return -1;
	}
	if((err=pthread_mutex_lock(&mux_pollusers))!=0){
	    errno=err;
	    fprintf(stderr,"Errore nel prendere la lock; Funzione listener; Variabile users\n");
	    perror("lock");
	    //aggiorno le statistiche:errori++
	    if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
		fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
	    return -1;
	}
	ret=poll(poll_set, pollusers, 0);
	//printf("Main: numero utenti poll=%d\n", pollusers);//CONTROLLARE SE NON FUNZIONA. INSERIRE FORSE NUEMRO DI FD DA CONTROLLARE INVECE DEL MAX FD
	if((err=pthread_mutex_unlock(&mux_pollusers))!=0){
	    errno=err;
	    fprintf(stderr,"Errore nel prendere la lock; Funzione listener; Variabile users\n");
	    perror("lock");
	    //aggiorno le statistiche:errori++
	    if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
		fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
	    return -1;
	}
	if((err=pthread_mutex_unlock(&mux_poll))!=0){
	    errno=err;
	    fprintf(stderr,"Errore nel rilasciare la lock; Funzione main; Struttura poll\n");
	    perror("unlock");
	    //aggiorno le statistiche:errori++
	    if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
		fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
	    return -1;
	}
	switch(ret){
	    case (-1):{  //la poll ha restituito un errore
		switch(errno){
		    case EINTR:{  //la poll è stata interrotta da un segnale
		    } break;
		    default:{
			count_err++;
			//aggiorno le statistiche:errori++
			if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
			    fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
			if(count_err>3){  //ci sono stati 3 errori consecutivi quindi termino il server
			    perror("poll");
			    failure++;
			}
			else
			    fprintf(stderr,"La poll ha restituito un errore; Funzione server\n");
		    }break;
		}
	    }break;
	    case(0):{  //la poll è stata interrotta dal timeout e nessun evento è stato registrato
	    } break;
	    default:{  //tutto è andato a buon fine e la poll ha restituito il numero di fd con attività
		printf("Main ho trovato il client\n");
		if (ret<-1){
		    fprintf(stderr,"Errore nella funzione poll; Funzione main\n");
		    //aggiorno le statistiche:errori++
		    if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
			fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
		    count_err++;
		    break;
		}
		count=0;
		i=0;
		while(i<size_poll || count==ret){  //cerco gli fd con attività
		    if((err=pthread_mutex_lock(&mux_poll))!=0){
			errno=err;
			fprintf(stderr, "Errore nel prendere la lock; Funzione main; Struttura poll\n");
			perror("lock");
			//aggiorno le statistiche:errori++
			if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
			    fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
			return -1;
		    }
		    if(poll_set[i].fd!=-1){
			if(poll_set[i].revents & POLLIN){  //un client ha qualche operazione da svolgere
			    count++;
			    poll_set[i].revents=0; 
			    //acquisisco la lock sulla lista delle operazioni
			    if((err=pthread_mutex_lock(&mux_fd_operation))!=0){
				errno=err;
				fprintf(stderr, "Errore nel prendere la lock; Funzione main; Struttura fd_operation\n");
				perror("lock");
				//aggiorno le statistiche:errori++
				if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
				    fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
				return -1;
			    }
			    //inserisco nella lista l'fd del client che vuole svolgere un'operazione
			    if(fd_operation==NULL){
				fd_operation=(fd_list*)malloc(sizeof(fd_list));
				fd_operation->fd=poll_set[i].fd;
				fd_operation->next=NULL;
			    }
			    else{
				fd_list *corr=fd_operation;
				while(corr->next!=NULL)
				    corr=corr->next;
				corr->next=(fd_list*)malloc(sizeof(fd_list));
				corr=corr->next;
				corr->fd=poll_set[i].fd;
				corr->next=NULL;
			    }
			    if((err=pthread_cond_signal(&cond_operation))!=0){  //faccio una signal per svegliare un worker
				errno=err;
				fprintf(stderr,"Errore nell'effetuare la signal; Funzione main; Struttura fd_operation\n");
				perror("signal");
				//aggiorno le statistiche:errori++
				if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
				    fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
				return -1;
			    }
			    if((err=pthread_mutex_unlock(&mux_fd_operation))!=0){
				errno=err;
				fprintf(stderr,"Errore nel rilasciare la lock; Funzione main; Struttura fd_operation\n");
				perror("unlock");
				//aggiorno le statistiche:errori++
				if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
				    fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
				return -1;
			    }
			    poll_set[i].fd=-1;  //lo levo dal set della poll e lo inserisco, dal worker, alla fine dell'operazione
			    if((modify_pollusers_number(-1))!=0){  //decremento il numero di utenti dal set della poll
				fprintf(stderr,"Errore nel decrementare il numero di utenti della poll; Funzione main\n");
				//aggiorno le statistiche:errori++
				if((update_stats(0,0,0,0,0,0,1,0,0))!=0)
				    fprintf(stderr, "Errore nell'aggiornamento delle statistiche\n");
				failure++;
			    }
			}
...
Il codice del main continua con il controllo degli errori o della chiusura di qualche connessione ecc

EDIT: dovrei aver risolto quel problema ma appena provo a leggere con la read quello che mi scrive il client mi viene restituito questo errore: Read: Connection reset by peer
Cosa significa questo errore? Come potrei sistemarlo?