Visualizzazione dei risultati da 1 a 9 su 9
  1. #1
    Utente di HTML.it L'avatar di goatboy
    Registrato dal
    Mar 2011
    residenza
    Salerno
    Messaggi
    408

    [C] Problema comunicazione client-server

    Salve a tutti.
    Sto provando a realizzare un client-server echo in C. Echo nel senso che il server risponde con la stessa cosa che gli invia il client. E fin qui, nessun problema. Nel momento in cui provo a modificarlo per far sì che il server, anzichè rispondere con lo stesso messaggio, risponda con un messaggio standard, del tipo "Messaggio ricevuto.", non riesco più a farlo funzionare. Dove sbaglio?

    In breve, la funzione del server in cui ricevo la stringa e rispondo con un messaggio standard è questa:
    codice:
    void server_echo(int sockfd){
        ssize_t        n;
        char        line[MAXLINE];
        char        ack[] = "Message Received";
        
        for( ; ; ){
            if( (n = reti_readline(sockfd, line, MAXLINE)) == 0)
                return; // Connessione chiusa dal client
            // Se inserisco line ed n al posto di ack e strlen(ack) funziona tutto correttamente
            reti_writen(sockfd, ack, strlen(ack)); 
        }
    }
    Analogamente, la funzione del client è questa:
    codice:
    void client_echo(FILE *fp, int sockfd){
        char sendline[MAXLINE], recvline[MAXLINE];
        while(fgets(sendline, MAXLINE, fp) != NULL){
            reti_writen(sockfd, sendline, strlen(sendline));
            if(reti_readline(sockfd, recvline, MAXLINE) == 0){
                printf("%s: server terminated prematurely", __FILE__);
                exit(1);
            }
            fputs(recvline, stdout);
        }
    }
    La funzione reti_readline prende in input un socket descriptor e un vettore di caratteri di lunghezza MAXLINE (256). Termina quando incontra \n. La funzione reti_writen scrive n byte sul descrittore.

  2. #2
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,462
    Prova con

    strlen(ack)+1
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  3. #3
    Utente di HTML.it L'avatar di goatboy
    Registrato dal
    Mar 2011
    residenza
    Salerno
    Messaggi
    408
    Non cambia nulla. Ho notato che se chiudo il server mentre il client è ancora aperto, il client riceve "Message Received".

  4. #4
    devi fornire anche il codice per l invio e la ricezione delle linee.

  5. #5
    Hai controllato che con un packet sniffer (tipo Wireshark) il messaggio sia inviato/ricevuto?
    Comunque posta anche reti_writen e reti_readline.

    Inoltre
    codice:
      reti_writen(sockfd, sendline, strlen(sendline));
            if(reti_readline(sockfd, recvline, MAXLINE)==0){
                printf("%s: server terminated prematurely", __FILE__);
                exit(1);
            }
    ha due errori: 1) non controlli se reti_writen ha fallito/succeduto e 2) se reti_readline ritorna 0, tipicamente indica che la chiamata ha avuto successo, quindi non termini l'applicazione.
    Ed i socket vanno chiusi quando hai finito.
    Ultima modifica di signoredeltempo; 25-04-2015 a 16:30

  6. #6
    Utente di HTML.it L'avatar di goatboy
    Registrato dal
    Mar 2011
    residenza
    Salerno
    Messaggi
    408
    Le funzioni reti_readline e reti_writen sono queste (fornite dal professore):

    codice:
    /***************************************************************************
     *  reti_read
     *  legge tutti i dati disponibili nel buffer in una sola volta e poi li
     *  esamina un byte per volta. La read, invece, legge un byte per volta. 
     ***************************************************************************/
    ssize_t reti_read(int fd, char *ptr) {
            static int      read_cnt = 0;  /* numero di byte letti */
            static char     read_buf[MAXLINE]; /* buffer per mantenere i dati letti */
            static char     *read_ptr; /* puntatore al prossimo byte da leggere */
    
            if (read_cnt <= 0) {
                    /* se non ci sono byte disponibili nel buffer chiama la read. */
                    while ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) 
                          /* se la read fallisce perchè non ci sono sufficienti
                             dati riprova, altrimenti esce. */
                          if (errno != EINTR)
                              return(-1);
                    if (read_cnt == 0)
                          return(0);
                    read_ptr = read_buf;
            }
    
            /* legge il prossimo byte dal buffer e decrementa il numero dei byte 
               disponibili */
            read_cnt--;
            *ptr = *read_ptr++;
            return(1);
    }
    
    
    /***************************************************************************
     *  reti_readline
     *  legge un'intera riga utilizzando la reti_read 
     ***************************************************************************/
    ssize_t reti_readline(int fd, void *vptr, size_t maxlen) {
            int     n, rc;
            char    c, *ptr;
    
            ptr = vptr;
            for (n = 1; n < maxlen; n++) {
                if ( (rc = reti_read(fd, &c)) == 1) {
                    *ptr++ = c;
                    if (c == '\n')
                       break;       /* legge il newline, come la fgets() */
                } 
                else 
                    if (rc == 0) {
                       if (n == 1)
                            return(0);      /* EOF, non ha letto nulla */
                       else
                            break;          /* EOF, ha letto qualcosa */
                    } 
                    else
                       return(-1);          /* errore, errno settato dalla read() */
            }
    
            *ptr = 0;       /* inserisce uno 0 per indicare la fine dell'input, coma la fgets() */
            return(n);
            /* restituisce il numero di byte letti */
    }
    
    
    /***************************************************************************
     *  reti_writen 
     *  scrive n byte sul descrittore fd. Riprova fino a quando i dati non
     *  vengono effettivamenti scritti. 
     ***************************************************************************/
    ssize_t reti_writen(int fd, const void *vptr, size_t n) {
            size_t          nleft;    /* byte anora da scrivere */
            ssize_t         nwritten; /* byte scritti dall'ultima write */
            const char      *ptr;
    
            ptr = vptr;
            nleft = n;
            while (nleft > 0) {
                    if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
                       if (errno == EINTR)
                          /* richiama la write se la funzione è fallita perchè
                             nel buffer ptr non ci sono sufficienti byte. */
                          nwritten = 0;
                       else
                          return(-1);
                    }
    
                    nleft -= nwritten;
                    ptr   += nwritten;
            }
            return(n);
            /* restituisce il numero di byte scritti. */
    }
    Il codice, inoltre, è al 99% uguale a quello del professore. Eventuali modifiche di ottimizzazione devono, probabilmente, essere ancora spiegate al corso quindi chiedo scusa se il codice non è performante
    Ultima modifica di goatboy; 25-04-2015 a 17:15

  7. #7
    il problema come immaginavo è che ru valuti solo l uscita 0 e non la -1.
    Nel server avrai una cosa simile a questa:
    codice:
    while((n = reti_readline(sockfd, line, MAXLINE))> 0)
                reti_writen(sockfd, ack, strlen(ack)); 
    puts("debug server exit while");
    

    togliendo il for;;

    nel client avrai:
    codice:
    
    
    codice:
    while(fgets(sendline, MAXLINE, fp)){
            if ( reti_writen(sockfd, sendline, strlen(sendline)) <= 0) ...error
            if(reti_readline(sockfd, recvline, MAXLINE)<=0){
                printf("%s: server terminated prematurely", __FILE__);
                exit(1);
            }
            fputs(recvline, stdout);
            fflush(stdout);
    }


    scusa per il codice ma al phone fatico a far meglio

  8. #8
    dimenticavo il messaggio ack deve terminare con "\n"
    ...
    ack[]=".....\n"

  9. #9
    Utente di HTML.it L'avatar di goatboy
    Registrato dal
    Mar 2011
    residenza
    Salerno
    Messaggi
    408
    Grazie vbextreme per i consigli. Ho provato a modificare come mi hai detto e in effetti il server mi rispondeva con un messaggio ma erano caratteri strani quindi qualcosa comunque non andava. Provando, invece, a inserire soltanto \n ad ack funziona tutto correttamente. Proverò poi a sistemare il resto del codice. Grazie!

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.