首页 > 解决方案 > C TCP客户端-服务器分段故障问题

问题描述

我正在尝试使用 TCP 在 C 中实现客户端-服务器程序以进行练习。服务器应该能够为许多客户端提供服务。客户端请求服务器发送给他们的一些文件。每次客户端结束时,服务器都会因分段错误错误而崩溃。它打印“服务结束”,查看 gdb 它也返回到主函数,但在循环内调用“服务”函数后它从不打印“prova”。

在这里您可以看到我的服务器和我的客户端下方

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

标签: csocketsnetworking

解决方案


推荐阅读