为什么TCP客户端正确发送了char数组,但服务器却读不到?

问题描述 投票:0回答:1

我有一个客户端,它要求用户提供车牌,然后(创建 TCP 套接字后)将其发送到服务器。我非常有信心客户端上的这一步是正确的,因为客户端在输出中显示的正是它应该发送的内容,车牌和 8 字节正是我想要的(第 57-66 行)。

服务器的问题是,它是一个可以使用

select()
同时处理UDP和TCP的服务器,在接受TCP连接后,
read()
函数返回0,所以这意味着服务器基本上没有读取任何内容? (第221-227行),
errno
内的
perror()
表示
Read: interrupted System call

可能这是一个小错误,但是每次我写这种类型的代码时我总是会遇到这种问题,所以我想知道为什么会发生。

这是客户:

//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);
}

这是服务器(我正在努力解决的部分从第 221 行开始,下面的 UDP 部分和上面的

select()
应该是正确的):

#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 */

}
c sockets client-server system-calls serversocket
1个回答
0
投票

在您的服务器中,第 221 行,您缺少一些必需的括号。

在此行:

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

您将

letto
设置为错误的值,因为
<=
运算符的优先级高于
=
运算符,因此编译器在评估
read(...) <= 0
之前先评估
letto = ...
,因此您最终设置了
 的值letto
<=
的结果,而不是
read()
的结果。

该行需要像这样:

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

将此与您的客户端代码进行比较,其中第 60 行和第 67 行具有类似的语句,并且正确使用了额外的括号:

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

这就是为什么我总是建议人们不要在同一个语句中分配变量并比较其值!你应该将它们分开以避免这个问题,例如:

letto = read(connfd, targa, sizeof(targa));
if (letto <= 0) {
© www.soinside.com 2019 - 2024. All rights reserved.