Why does the TCP client send the char array correctly but the server can't read it?

71 Views Asked by At

I have a client which asks the user for a car plate and then (after creating a TCP socket) sends it to the server. I'm quite confident that this step on the client is correct, because what the client shows in the output is exactly what it should be sent, the car plate and 8 byte which is exactly what I want (line 57-66).

The problem with the server, which is a server that can handle both UDP and TCP using select(), is that after accepting the TCP connection the read() function returns 0, so it means that the server has read nothing basically? (line 221-227), the errno inside the perror() says Read: interrupted System call.

Probably it is a small error, but every time I write this type of code I always face this kind of problem, so I would like to know why it happens.

Here's the client:

//librerie da includere
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/limits.h>

int main(int argc,char ** argv){
    
    int port,sd;
    //host e servaddr
    struct hostent    *host; //host server
    struct sockaddr_in servaddr; //server a cui il client si deve connettere
    
    /* INIZIALIZZAZIONE INDIRIZZO SERVER -------------------------- */
    memset((char *)&servaddr, 0, sizeof(struct sockaddr_in));
    servaddr.sin_family = AF_INET;
    /*
    * NOTA: gethostbyname restituisce gli indirizzi gia' in formato di rete
    */
    host = gethostbyname(argv[1]);
    if (host == NULL) {
        printf("%s not found in /etc/hosts\n", argv[1]);
        exit(1);
    }
    
    port = atoi(argv[2]);//porta usare ATOI
    
    //SETTARE IL SERVER A CUI ASSOCIARE LA SOCKET
    servaddr.sin_addr.s_addr = ((struct in_addr *)(host->h_addr))->s_addr;
    servaddr.sin_port        = htons(port);
    
    //CREIAMO UNA SOCKET (SD INTERO TRATTATA COME FILE)
    sd = socket(AF_INET, SOCK_STREAM, 0);
    if (sd < 0) {
            perror("apertura socket");
            exit(1);
    }
    
    /* Operazione di BIND implicita nella connect */
    if (connect(sd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) < 0) {
        perror("connect");
        exit(1);
    }
    printf("Client: connect ok\n");
    char targa[8];
    char nomeFile[PATH_MAX];
    printf("Dimmi la targa\n");
    int scritto;
    while(fgets(targa,sizeof(targa),stdin)){
        while (getchar()!='\n') ;  // svuoto il buffer da tastiera
        targa[7]='\0';
        printf("invio: %s\n",targa);
        if((scritto=write(sd,targa,strlen(targa)+1))<=0){
            printf("Errore write\n");
            perror("Errore write");
            continue;
        }
        printf("Ho scritto %d\n",scritto);
        int letto; 
        while((letto=read(sd,nomeFile,sizeof(nomeFile)))!=0){

            if(letto==-1){
                perror("Errore read");
                continue;
            }
        
            printf("Ricevuto file %s\n",nomeFile);
            int fd=creat(nomeFile,O_CREAT | O_TRUNC | S_IRUSR | S_IWUSR);
            if(fd<0){
                perror("Errore creazione file");
                continue;
            }
            char temp;
            int uscito=-1;
            while(read(sd,&temp,1)){
                if(temp!='\0'){
                    write(fd,&temp,1);
                }
                else{
                    close(fd);
                    uscito=0;
                }
            }
            if(uscito==-1)
                close(fd);
        }
        close(sd);
        sd = socket(AF_INET, SOCK_STREAM, 0);   
        if (connect(sd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) < 0) {
            perror("connect");
            exit(1);
        }
        printf("Dimmi la targa\n");
    }
    close(sd);
}

Here's the server (the part that I'm struggling with starts at line 221, the UDP part below and the select() above should be correct):

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/select.h>
#include <linux/limits.h>

#define N 10

int max(int a, int b)
{
    return (a > b) ? a : b;
}

/********************************************************/
void gestore(int signo)
{
    int stato;
    printf("esecuzione gestore di SIGCHLD\n");
    wait(&stato);
}
/********************************************************/


typedef struct {
    char targa[20];
    char patente[6];
    char tipo[64];
    char img[64];
}Prenotazione;

typedef struct {
    char targa[8];
    char patente[6];
}Richiesta;

typedef struct {
    Prenotazione indice[N];
}Tabella;

int main(int argc,char ** argv){
    int listenfd, connfd, udpfd, nready, maxfdp1;
    fd_set rset;
    struct sockaddr_in cliaddr, servaddr;
    int len;
    const int on=1;
    char targa[8];
    char pathImg[13];
    Prenotazione *p=malloc(sizeof( Prenotazione));
    Richiesta * r=malloc(sizeof(Richiesta));
    Tabella tabella;

    char str[20];
    int cont=3;

    strcpy(tabella.indice[0].targa, "AB745LK");
    strcpy(tabella.indice[0].patente, "00001");
    strcpy(tabella.indice[0].tipo, "auto");
    strcpy(str, tabella.indice[0].targa);
    strcat(str, "_img/");
    strcpy(tabella.indice[0].img, str);

    strcpy(tabella.indice[1].targa, "AS734LE");
    strcpy(tabella.indice[1].patente, "00002");
    strcpy(tabella.indice[1].tipo, "camper");
    strcpy(str, tabella.indice[1].targa);
    strcat(str, "_img/");
    strcpy(tabella.indice[1].img, str);

    strcpy(tabella.indice[2].targa, "RT657GH");
    strcpy(tabella.indice[2].patente, "00003");
    strcpy(tabella.indice[2].tipo, "auto");
    strcpy(str, tabella.indice[2].targa);
    strcat(str, "_img/");
    strcpy(tabella.indice[2].img, str);
    /* CONTROLLO ARGOMENTI ---------------------------------- */
    if (argc != 2)
    {
        printf("Error: %s port\n", argv[0]);
        exit(1);
    }
    
    int nread = 0;
    while (argv[1][nread] != '\0')
    {
        if ((argv[1][nread] < '0') || (argv[1][nread] > '9'))
        {
            printf("Terzo argomento non intero\n");
            exit(2);
        }
        nread++;
    }
    int port = atoi(argv[1]);
    if (port < 1024 || port > 65535)
    {
        printf("Porta scorretta...");
        exit(2);
    }
    
    /* INIZIALIZZAZIONE INDIRIZZO SERVER E BIND ---------------------------- */
    memset((char *)&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(port);
    printf("Server avviato\n");

    /* CREAZIONE SOCKET TCP ------------------------------------------------ */
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd < 0)
    {
        perror("apertura socket TCP ");
        exit(1);
    }
    printf("Creata la socket TCP d'ascolto, fd=%d\n", listenfd);

    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
    {
        perror("set opzioni socket TCP");
        exit(2);
    }
    printf("Set opzioni socket TCP ok\n");

    if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("bind socket TCP");
        exit(3);
    }
    printf("Bind socket TCP ok\n");

    if (listen(listenfd, 5) < 0)
    {
        perror("listen");
        exit(4);
    }
    printf("Listen ok\n");

    /* CREAZIONE SOCKET UDP ------------------------------------------------ */
    udpfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (udpfd < 0)
    {
        perror("apertura socket UDP");
        exit(5);
    }
    printf("Creata la socket UDP, fd=%d\n", udpfd);

    if (setsockopt(udpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
    {
        perror("set opzioni socket UDP");
        exit(6);
    }
    printf("Set opzioni socket UDP ok\n");

    if (bind(udpfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("bind socket UDP");
        exit(7);
    }
    printf("Bind socket UDP ok\n");
    
    /* AGGANCIO GESTORE PER EVITARE FIGLI ZOMBIE -------------------------------- */
    signal(SIGCHLD, gestore);

    /* PULIZIA E SETTAGGIO MASCHERA DEI FILE DESCRIPTOR ------------------------- */
    FD_ZERO(&rset);
    maxfdp1 = max(listenfd, udpfd) + 1;

    /* CICLO DI RICEZIONE EVENTI DALLA SELECT ----------------------------------- */
    for (;;)
    {
        FD_SET(listenfd, &rset);
        FD_SET(udpfd, &rset);

        if ((nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0)
        {
            if (errno == EINTR)
                continue;
            else
            {
                perror("select");
                exit(8);
            }
        }

    /* GESTIONE RICHIESTE TCP ------------------------------------- */
        if (FD_ISSET(listenfd, &rset))
        {
            len = sizeof(struct sockaddr_in);
            if ((connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &len)) < 0)
            {
                if (errno == EINTR)
                    continue;
                else
                {
                    perror("accept");
                    exit(9);
                }
            }

            if (fork() == 0)
            { /* processo figlio che serve la richiesta di operazione */
                close(listenfd);
                char pwd[PATH_MAX];
                if(getcwd(pwd,sizeof(pwd))==0){
                    printf("Errore getcwd\n");                             //restituisce pwd
                    perror("Error getcwd");
                    exit(0);
                }
                printf("pwd :%s\n",pwd);
                printf("Dentro il figlio, pid=%i\n", getpid());
                int letto;
                if (letto = read(connfd, targa, sizeof(targa)) <= 0) {
                    printf("Errore read, letti %d byte\n", letto);
                    perror("Read");
                    exit(1);
                }
                targa[letto] = '\0';
                printf("Targa: %s \n",targa);
                strcpy(pathImg,targa);
                strcat(pathImg,"_img/");
                char Path[PATH_MAX];
                sprintf(Path,"%s/%s",pwd,pathImg);
                printf("Percorso directory %s\n",Path);

                DIR *imgDir = opendir(Path);//apro directory
                struct dirent *dp; //struttura su cui passare i vari file della directory
                if (imgDir == NULL)
                {
                    perror("Errore apertura file");
                    continue;
                }
                while((dp = readdir(imgDir)) != NULL){
                    struct stat * statFile;
                    char filePath[PATH_MAX];
                    sprintf(filePath,"%s/%s",Path,dp->d_name);
                    if(stat(filePath,statFile)<0){
                        perror("Error stat file");
                        closedir(imgDir);
                        exit(EXIT_FAILURE);
                    }
                    if(S_ISREG(statFile->st_mode)){
                        if(write(connfd,dp->d_name,sizeof(dp->d_name)<=0)){
                            perror("Errore write");
                            break;
                        }
                        int fd=open(filePath,O_RDONLY);
                        if(fd<0){
                            perror("Errore File");
                            break;
                        }
                        char temp;
                        while(read(fd,&temp,1)>0){
                            if(write(connfd,&temp,1)<=0){
                                perror("Errore write file");
                                break;
                            }
                        }
                        temp='\0';
                        if(write(connfd,&temp,1)<=0){
                            perror("Error write socket");
                            continue;
                        }
                    }
                }
                closedir(imgDir);
                printf("Figlio %i: termino\n", getpid());
                shutdown(connfd, 0);
                shutdown(connfd, 1);
                close(connfd);
                exit(EXIT_SUCCESS);
            } // figlio-fork
            /* padre chiude la socket dell'operazione */
            shutdown(connfd,0);
            shutdown(connfd,1);
            close(connfd);
        } /* fine gestione TCP */     
    
    /* GESTIONE UDP ------------------------------------------ */
        if (FD_ISSET(udpfd, &rset))
        {

            len = sizeof(struct sockaddr_in);

            if(recvfrom(udpfd,r,sizeof(Richiesta),0, (struct sockaddr *)&cliaddr, &len)<0){
                perror("recvfrom");
                continue;
            }
            printf("Ricevuta richiesta UDP\n");
            printf("Targa:%s \t Patente:%s\n",r->targa,r->patente);
            short esito=-1;
            for(int i=0;i<cont;i++){
                if(strcmp(tabella.indice[i].targa,r->targa)==0){
                    strcpy(tabella.indice[i].patente,r->patente);
                    esito=0;
                    printf("Prenotazione modificata\n:");
                    printf("Targa:%s \t Patente:%s\n",tabella.indice[i].targa,tabella.indice[i].patente);
                }
            }
            short shortrete = htons(esito);
            if (sendto(udpfd, &esito, sizeof(esito), 0, (struct sockaddr *)&cliaddr, len) < 0) {
                perror("Sendto error");
                continue;
            }

            close(udpfd);

        //operazioni server.....
        } /* fine gestione richieste di conteggio */

    } /* ciclo for della select */
    /* NEVER ARRIVES HERE */

}
1

There are 1 best solutions below

7
Remy Lebeau On

In your server, on line 221, you are missing some required parenthesis.

On this line:

if (letto = read(connfd, targa, sizeof(targa)) <= 0) {

You are setting letto to the wrong value, as the <= operator has higher precedence than the = operator. The compiler will evaluate read(...) <= 0 before it evaluates letto = ..., so you end up setting the value of letto to the result of <= rather than the result of read().

That line needs to be like this instead:

if ((letto = read(connfd, targa, sizeof(targa))) <= 0) {
    ^                                          ^

Compare this to your client code, where lines 60 and 67 have similar statements that are using the extra parenthesis correctly:

if((scritto=write(sd,targa,strlen(targa)+1))<=0){
   ^                                       ^
...
while((letto=read(sd,nomeFile,sizeof(nomeFile)))!=0){
      ^                                        ^

This is why I always advise people NOT to assign a variable and compare its value in the same statement! You should separate them to avoid this problem, eg:

letto = read(connfd, targa, sizeof(targa));
if (letto <= 0) {