为什么这个C程序(使用套接字和文件处理)在文件末尾添加不需要的字符?

时间:2015-11-18 15:34:12

标签: c sockets file-handling

程序:在这个项目中,我必须读取客户端程序中的文件,并将其发送到服务器程序

问题:在生成的文件中,我得到了客户端程序中的所有字符,以及最后的一些不需要的字符。

我认为原因是:如果我在要发送的文件中放入15个字符,我会得到正确的输出(请注意,我的缓冲区大小,即我一次发送的字符数是16)。如果我使用14个或更少的字符,我得到1' \ 00'在末尾。如果我使用更少的字符,那么我会得到一个' \ 00'对应于每个缺失的。也许我的' \ 0' (这就是我设置空格,或缓冲区中的额外字符)在输出文件中表示为' \ 00'。

这是客户端程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>

#define BUFSIZE 16

#define USAGE                                                                 \
"usage:\n"                                                                    \
"  transferclient [options]\n"                                                \
"options:\n"                                                                  \
"  -s                  Server (Default: localhost)\n"                         \
"  -p                  Port (Default: 8888)\n"                                \
"  -o                  Output file (Default foo.txt)\n"                       \
"  -h                  Show this help message\n"

/* Main ========================================================= */
int main(int argc, char **argv) {
    int option_char = 0;
    char *hostname = "127.0.0.1";
    unsigned short portno = 8888;
    char *filename = "foo.txt";

    // Parse and set command line arguments
    while ((option_char = getopt(argc, argv, "s:p:o:h")) != -1) {
        switch (option_char) {
            case 's': // server
            hostname = optarg;
                break;
            case 'p': // listen-port
                portno = atoi(optarg);
                break;
            case 'o': // filename
                filename = optarg;
                break;
            case 'h': // help
                fprintf(stdout, "%s", USAGE);
                exit(0);
                break;
            default:
                fprintf(stderr, "%s", USAGE);
                exit(1);
    }
    }

    /* Socket Code Here */
    int sockfd = 0, n = 0;
    char recvBuff[BUFSIZE], sendBuff[BUFSIZE];
    struct sockaddr_in serv_addr;

    if((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0) {
        printf("Error: Could not create socket \n");
        return 1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(portno);
    serv_addr.sin_addr.s_addr = inet_addr(hostname);

    if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0) {
        printf("Error: Connect Failed\n");
        return 1;
    }

    FILE *fp = fopen(filename, "rb");
    if(fp == NULL) {
        printf("Error: file not found.\n");
        return 0;
    }

    fseek(fp, 0, SEEK_END);
    int size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    memset(sendBuff, '\0', BUFSIZE);
    sprintf(sendBuff, "%d", size);
    write(sockfd, sendBuff, strlen(sendBuff));
    printf("size: %d\n", size);

    memset(sendBuff, '\0', BUFSIZE);
    int temp = fread(sendBuff, 1, BUFSIZE, fp);

    while(temp > 0) {
        write(sockfd, sendBuff, BUFSIZE);
        memset(sendBuff, '\0', BUFSIZE);
        temp = fread(sendBuff, 1, BUFSIZE, fp);
    }

    fclose(fp); 
    printf("done sending data to server.\n");

    memset(recvBuff, '\0', BUFSIZE);
    while((n = read(sockfd, recvBuff, BUFSIZE)) > 0) {
        recvBuff[n] = '\0';
        if(fputs(recvBuff, stdout) == EOF) {
            printf("Error: Fputs error\n");
        }
        printf("\n");
    }

    if( n < 0) {
        printf("Read Error\n");
    }

    return 0;
}

这是服务器程序:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>

#if 0
/*
 * Structs exported from netinet/in.h (for easy reference)
 */

/* Internet address */

struct in_addr {
  unsigned int s_addr;
};

/* Internet style socket address */
struct sockaddr_in  {
  unsigned short int sin_family; /* Address family */
  unsigned short int sin_port;   /* Port number */
  struct in_addr sin_addr;   /* IP address */
  unsigned char sin_zero[...];   /* Pad to size of 'struct sockaddr' */
};

/*
 * Struct exported from netdb.h
 */

/* Domain name service (DNS) host entry */
struct hostent {
  char    *h_name;        /* official name of host */
  char    **h_aliases;    /* alias list */
  int     h_addrtype;     /* host address type */
  int     h_length;       /* length of address */
  char    **h_addr_list;  /* list of addresses */
}
#endif

#define BUFSIZE 4096
#define CLIENTBUFSIZE 16

#define USAGE                                                                 \
"usage:\n"                                                                    \
"  transferserver [options]\n"                                                \
"options:\n"                                                                  \
"  -p                  Port (Default: 8888)\n"                                \
"  -f                  Filename (Default: bar.txt)\n"                         \
"  -h                  Show this help message\n"

int num_of_digits(int num) {
    if(num <= 0) printf("Error: size <= 0.\n");
    if(num <= 0) exit(1);

    int n = 0;
    while(num > 0) {
        n++;
        num /= 10;
    }

    return n;
}

int main(int argc, char **argv) {
    int option_char;
    int portno = 8888; /* port to listen on */
    char *filename = "bar.txt"; /* file to transfer */

    // Parse and set command line arguments
    while ((option_char = getopt(argc, argv, "p:f:h")) != -1){
        switch (option_char) {
            case 'p': // listen-port
                portno = atoi(optarg);
                break;
            case 'f': // listen-port
                filename = optarg;
                break;
            case 'h': // help
                fprintf(stdout, "%s", USAGE);
                exit(0);
                break;
            default:
                fprintf(stderr, "%s", USAGE);
                exit(1);
        }
     }

    /* Socket Code Here */
    int listenfd = 0, connfd = 0;

    struct sockaddr_in serv_addr;

    char sendBuff[BUFSIZE], recvBuff[BUFSIZE];  

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    printf("socket retrieve success\n");

    memset(&serv_addr, '0', sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;    
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    serv_addr.sin_port = htons(portno);    

    bind(listenfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));

    if(listen(listenfd, 5) == -1) {
        printf("Failed to listen\n");
        return -1;
    }

    int size, temp;

    while(1) {
        connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); // accept awaiting request

        memset(recvBuff, '\0', BUFSIZE);
        read(connfd, recvBuff, BUFSIZE);

        sscanf(recvBuff, "%d", &size);
        temp = strlen(recvBuff) - num_of_digits(size);
        size -= temp;

        printf("size: %d\n", size);
        printf("Data from client:\n%s", (recvBuff + num_of_digits(size)));

        FILE * fp = fopen(filename, "wb");
        int temp;
        while(size > 0) {
            read(connfd, recvBuff, CLIENTBUFSIZE);
            printf("%s", recvBuff);
            temp = fwrite(recvBuff, 1, CLIENTBUFSIZE, fp);
            size -= temp;
            printf("temp: %d\n", temp);
            printf("Remaining data: %d\n", size);
        }
        fclose(fp);
        printf("size: %d\n", size);
        printf("\n\nFinished reading from client.\n");

        strcpy(sendBuff, "Message from server: your message has been recieved.");
        write(connfd, sendBuff, strlen(sendBuff));


        close(connfd);    
        sleep(1);
    }

    return 0;
}

这里是输入文件内容:

  

12345678901234

这里是输出文件内容:

  

12345678901234

     

\ 00

1 个答案:

答案 0 :(得分:1)

read()系统调用返回读取的字节数(或-1表示错误)。您将结果丢弃并将CLIENTBUFSIZE字节的整个缓冲区写入您的文件,即使您发送的字节少于16个字节。