C Ошибка сбоя сегментации клиент-сервер TCP - PullRequest
0 голосов
/ 21 апреля 2019

Я пытаюсь реализовать клиент-серверную программу на C с TCP для упражнения. Сервер должен быть в состоянии обслуживать много клиентов. Клиенты запрашивают некоторые файлы, которые сервер отправляет им. Каждый раз, когда клиент заканчивается, сервер падает с ошибкой сегментации. Он печатает «конец службы», глядя на gdb, он также возвращает основной функции, но он никогда не печатает «prova» после вызова функции «service» внутри цикла.

Здесь вы можете увидеть мой сервер и ниже моего клиента

/*
 * TEMPLATE 
 */
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include <rpc/xdr.h>

#include <stdint.h>

#include <string.h>
#include <time.h>
#include <unistd.h>

#include "../errlib.h"
#include "../sockwrap.h"

#define BUFLEN      1024 /* Buffer length */

char *prog_name;
char *err="-ERR\r\n";

void service(int s);

uint32_t getFileCreationTime(char *filename);

int main (int argc, char *argv[])
{
    int     conn_request_skt;   /* passive socket */
        uint16_t    lport_n, lport_h;   /* port used by server (net/host ord.) */
    int     bklog = 2;      /* listen backlog */
    int     s;          /* connected socket */
    socklen_t   addrlen;
    struct sockaddr_in  saddr, caddr;   /* server and client addresses */ 

    prog_name = argv[0];    

    if (argc != 2) 
    {
        printf("Usage: %s <port number>\n", prog_name);
        exit(1);
    }

    /* get server port number */
    if (sscanf(argv[1], "%" SCNu16, &lport_h)!=1)
        err_sys("Invalid port number");
    lport_n = htons(lport_h);

    /* create the socket */
    printf("creating socket...\n");
    s = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    printf("done, socket number %u\n",s);

    /* bind the socket to any local IP address */
    bzero(&saddr, sizeof(saddr));
    saddr.sin_family      = AF_INET;
    saddr.sin_port        = lport_n;
    saddr.sin_addr.s_addr = INADDR_ANY;
    showAddr("Binding to address", &saddr);
    Bind(s, (struct sockaddr *) &saddr, sizeof(saddr));
    printf("done.\n");

    /* listen */
    printf ("Listening at socket %d with backlog = %d \n",s,bklog);
    Listen(s, bklog);
    printf("done.\n");

    conn_request_skt = s;

    /* main server loop */
    for (;;)
    {
        printf("loop again\n");
        /* accept next connection */
        addrlen = sizeof(struct sockaddr_in);
        s = Accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
        showAddr("Accepted connection from", &caddr);
        printf("new socket: %u\n",s);

        /* serve the client on socket s */
        service(s);
        printf("Prova\n");
    }


    return 0;
}

uint32_t getFileCreationTime(char *filename)
{
    struct stat *attr;
    stat(filename, attr);
    return attr->st_mtime;
}

void service(int s) 
{
        char rbuf[BUFLEN+1];        /* reception buffer */
        char buf[BUFLEN];       /* sending buffer */
        char sbuf[BUFLEN];      /* buffer that will contain the dimension of the file */
        int     n;
        char *get, *filename, filename_stats[20];
        size_t len;
        uint32_t bsent, dimension, modtime;
        FILE *fp;
        struct stat * fstatus;

        for (;;)
    {
        n=recv(s, rbuf, BUFLEN-1, 0);
        if (n < 0)
        {
            printf("Read error\n");
            close(s);
            printf("Socket %d closed\n", s);
            break;
        }
        else if (n==0)
        {
            printf("Connection closed by party on socket %d\n",s);
            close(s);
            break;
        }
        else
        {
            rbuf[n]=0;

            get = strtok(rbuf, " "); 
                filename = strtok(NULL, "\r\n");

            if(strcmp(get, "GET") == 0)
            {
                printf("\nA client requested the file '%s'\n", filename);

                fp = fopen(filename, "rb");
                if (fp == NULL)
                {
                    printf("-ERR\tCould not open the file\n");
                    if(writen(s, err, 6) != 6)
                        printf("Write error\n");
                }
                fseek (fp, 0, SEEK_END);
                dimension = ftell (fp);
                //dimension--;
                fseek (fp, 0, SEEK_SET);



                sprintf(sbuf, "+OK\r\n");               
                printf("Sending:\n%s\n", sbuf);
                if(writen(s, sbuf, 5) != 5)
                    printf("Write error\n");

                //printf("Sending:\n%d\n", dimension);
                //dimension = htonl(dimension);
                //printf("dimension net=%d\n", dimension);
                if(writen(s, &dimension, 4) != 4)
                    printf("Write error\n");
                //dimension = ntohl(dimension);
                printf("dimension=%d\n", dimension);

                bsent=0;
                while(bsent!=dimension)
                {
                    if(dimension-bsent < BUFLEN)
                    {
                        //printf("bytes to send <BUFLEN\n");

                        fread (buf, 1, dimension-bsent, fp);

                        printf("Sending last %d bytes of the file\n", dimension-bsent); 
                        if(writen(s, buf, dimension-bsent) != dimension-bsent)
                            printf("Write error\n");
                        bsent+=dimension-bsent;
                    }
                    else
                    {
                        //printf("bytes to send > BUFLEN\n");
                        fread (buf, 1, BUFLEN, fp);

                        //printf("Sending:\n%s\n", buf);    
                        if(writen(s, buf, BUFLEN) != BUFLEN)
                            printf("Write error\n");

                        bsent+=BUFLEN;
                        printf("Bytes sent: %d\n", bsent);
                    }

                }

                fclose (fp);

                modtime = getFileCreationTime(filename);

                printf("Sending:\n%d\n", modtime);
                //modtime = htonl(modtime);
                if(writen(s, &modtime, 4) != 4)
                    printf("Write error\n");

                printf("File '%s' correctly sent to the requesting client\n", filename);

            }
            else    //invalid request
            {
                printf("-ERR\tINVALID REQUEST\n");
                if(writen(s, err, 6) != 6)
                    printf("Write error\n");
            }                   
        }   
    }

    printf("End of service\n");
    return;
}

А вот и клиент:

/*
 * TEMPLATE 
 */
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <ctype.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include <rpc/xdr.h>

#include <stdint.h>

#include <string.h>
#include <time.h>
#include <unistd.h>

#include "../errlib.h"
#include "../sockwrap.h"

#define BUFLEN      1024 /* Buffer length */

char *prog_name;

int main (int argc, char *argv[])
{
    char buf[BUFLEN];       /* transmission buffer */
    char rbuf[BUFLEN];      /* receiving buffer */
    char ok[5];         /* buffer used to receive the "+OK" message */
    uint16_t tport_n, tport_h;  /* server port number (net/host ord) */
    char **filenames, *out="_out";

    FILE* fp;
    size_t  len;

    int s, result, i;
    struct sockaddr_in  saddr;      /* server address structure */
    struct in_addr  sIPaddr;    /* server IP addr. structure */

    ssize_t nreadok, nread;
    size_t nleft;
    uint32_t breceived , bytes, timestamp;


    prog_name = argv[0];

    if(argc<4)
    {
        printf("Error! Usage: %s IP_addr port_number filename1 filename2 filename3 ...\n", prog_name);
        return -1;
    }

    filenames = (char **) malloc(argc*sizeof(char*));

    for(i=3; i<argc; i++)
    {
        filenames[i-3] = (char*) malloc (30*sizeof(char));
        strcpy(filenames[i-3], argv[i]);
    }

    /* input IP address and port of server */
    result = inet_aton(argv[1], &sIPaddr);
    if (!result)
        err_quit("Invalid address");


    if (sscanf(argv[2], "%" SCNu16, &tport_h)!=1)
        err_quit("Invalid port number");
    tport_n = htons(tport_h);

    /* create the socket */
    printf("Creating socket\n");
    s = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    printf("done. Socket fd number: %d\n",s);

    /* prepare address structure */
    bzero(&saddr, sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port   = tport_n;
    saddr.sin_addr   = sIPaddr;

    /* connect */
    showAddr("Connecting to target address", &saddr);
    Connect(s, (struct sockaddr *) &saddr, sizeof(saddr));
    printf("done.\n");


    for(i=3; i<argc; i++)
    {
        //filename=argv[i];

        sprintf(buf, "GET %s\r\n", filenames[i-3]); //creating the request "GET filename"
        len = strlen(buf);
        printf("\n%s", buf);

        if(writen(s, buf, len) != len)  //sending the request
        {
            printf("Write error\n");
        }


        printf("\nwaiting for response...\n");


        //filename=argv[i];
        //char rbuf[BUFLEN];

        nread = readn(s, rbuf, 5);  //receiving "+OK\r\n"
        if(nread == 0)
            printf("Connection closed\n");


        if(rbuf[0] == '-')
        {
            nread = readn(s, rbuf, 1); //remaining byte of the "-ERR\r\n" message
            if(nread==0)
                printf("Connection closed\n");
            printf("-ERROR! The server could not answer the request\n");
            close(s);
            return -1;
        }

        bytes=0;
        //printf("Bytes 0=%d\n", bytes);
        nread = readn(s, &bytes, 4);    //receiving the dimension
        if(nread == 0)
            printf("Connection closed\n");
        //printf("Bytes net=%d\n", bytes);
        //bytes = ntohl(bytes);
        printf("Dimension of the file = %d\n", bytes);

        /*
        nread = readn(s, rbuf, bytes-1);    //receiving the file
        if(nread == 0)
            printf("Connection closed\n");

        */

        strcat(filenames[i-3], "_copy");
        fp = fopen(filenames[i-3], "wb");   //creating the file "filename_out" 
        if (fp == NULL)
        {
            printf("Could not open the file\n");
        }
        else
        {
            //coping data into the copy of the file
            breceived=0;
            while(1)
            {
                rbuf[0]=0;
                if(bytes-breceived < BUFLEN)
                {
                    //printf("bytes to receive <BUFLEN\n");
                    printf("Receiving: %d bytes of the file\n", bytes-breceived);   
                    if(readn(s, rbuf, bytes-breceived) != bytes-breceived)
                        printf("Connection closed\n");

                    //printf("receiving:\n%s\n", rbuf); 
                    //fputs(rbuf, fp);
                    fwrite(rbuf, 1, bytes-breceived, fp);

                    breceived+=bytes-breceived;
                    printf("Bytes received: %d\n", breceived);
                    break;
                }
                else
                {
                    printf("bytes to receive(>BUFLEN) = %d\n", bytes-breceived);
                    //printf("receiving:\n%s\n", rbuf); 
                    if(readn(s, rbuf, BUFLEN) != BUFLEN)
                        printf("Connection closed\n");

                    //printf("receiving:\n%s\n", rbuf);
                    //fputs(rbuf, fp);
                    fwrite(rbuf, 1, BUFLEN, fp);    

                    breceived=breceived+BUFLEN;
                    printf("Bytes received: %d\n", breceived);
                }
            }
        }

        if(rbuf[0] == '-')
        {
            nread = readn(s, rbuf, 1); //remaining byte of the "-ERR\r\n" message
            if(nread==0)
                printf("Connection closed\n");
            printf("-ERROR! The server could not answer the request\n");
            close(s);
            return -2;
        }

        //rbuf[bytes]=0;
        nread = readn(s, &timestamp, 4);    //receiving the timestamp
        if(nread == 0)
            printf("Connection closed\n");
        //timestamp = ntohl(timestamp);

        printf("\nFile received: '%s'\t %d bytes \t last mod: %d\n\n", filenames[i-3], bytes, timestamp);


        fclose(fp);
    }

    printf("Closing the connection\n");
    close(s);

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...