2014-10-17 67 views
0

我試圖做通過服務器 - 客戶關係通過TCP文件傳輸。然而,每當服務器收到客戶端請求的文件時,我都遇到了麻煩,它會在最後打印出帶有垃圾的請求文件名,然後繼續產生分段錯誤。此外,無論何時我將信息返回給客戶,文檔中的文本都以某種方式管理爲標題的一部分。我已經粘貼下面我的代碼爲我的服務器和客戶端Ç - TCP文件傳輸

Server.c

/*code for server portion of server-client setup*/ 
/*communication occurs overs TCP*/ 

#include <stdio.h>  /* for printf() and fprintf() */ 
#include <sys/socket.h> /* for socket(), bind(), and connect() */ 
#include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */ 
#include <stdlib.h>  /* for atoi() and exit() */ 
#include <string.h>  /* for memset() */ 
#include <unistd.h>  /* for close() */ 
#include <errno.h> /* for error numbers */ 
#include <dirent.h> /* for directories */ 

#define MAXPENDING 5 /* Maximum outstanding connection requests */ 
#define MAXLEN 255  /* Longest string */ 

void DieWithError(char *errorMessage); /* Error handling function */ 

int main(int argc, char *argv[]) 
{ 
    int servSock;      /* Socket descriptor for server */ 
    int clntSock;      /* Socket descriptor for client */ 
    struct sockaddr_in echoServAddr; /* Local address */ 
    struct sockaddr_in echoClntAddr; /* Client address */ 
    unsigned short echoServPort;  /* Server port */ 
    unsigned int clientOption, clntLen; /* Length of client address data structure */ 
    char data_recv[MAXLEN+1];  /* data received from client */ 
    int recvMsgSize;    /* size of message received */ 
    char data_sent[2000];  /* data sent to client */ 
    char file_request[50];  /* file requested by client */ 
    char file[2000];   /* last file sent to client */ 
    socklen_t len; 


    if (argc != 2)  /* Test for correct number of arguments */ 
    { 
     fprintf(stderr, "Usage: %s <Server Port>\n", argv[0]); 
     exit(1); 
    } 

    echoServPort = atoi(argv[1]); /* First arg: local port */ 

    /* Create socket for incoming connections */ 
    if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 
     DieWithError("socket() failed"); 

    /* Construct local address structure */ 
    memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */ 
    echoServAddr.sin_family = AF_INET;    /* Internet address family */ 
    echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */ 
    echoServAddr.sin_port = htons(echoServPort);  /* Local port */ 

    /* Bind to the local address */ 
    if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) 
     DieWithError("bind() failed"); 

    /* Mark the socket so it will listen for incoming connections */ 
    if (listen(servSock, MAXPENDING) < 0) 
     DieWithError("listen() failed"); 

    /* Wait for a client to connect */ 
    if ((clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, 
           &clntLen)) < 0) 
      DieWithError("accept() failed"); 

    /* Run Forever */ 
    while(atoi(data_recv) != -1){    
    /* Block until receive message from a client */ 
    if(recvMsgSize = recv(clntSock, data_recv, sizeof(data_recv), 0) < 0) 
    { 
     printf("Could not block socket. Failed with : %s\n", strerror(errno)); 
    } 
    printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr));  
    printf("%d\n", atoi(data_recv)); 
    recvMsgSize = 1000; 
    printf("%d\n", atoi(data_recv)); 
    char temp[255]; 

    switch(atoi(data_recv)){ 
     printf("%d\n", atoi(data_recv)); 
      case 1: 
      printf("Client has requested a list of all files\n"); 
       DIR * d; 
       struct dirent * dp; 
       d = opendir(".");    



       if(d != NULL){ 
        while((dp = readdir(d)) != NULL){ 
         if(dp->d_type == DT_REG){ 
          strcat(temp, dp->d_name); 
          strcat(temp, "\n"); 
         } 
        } 
        strcpy(data_recv, temp); 
        strcpy(temp, ""); 

         if(send(clntSock, data_recv, recvMsgSize, 0) < 0){ 
          printf("send() sent a different number of bytes than expected"); 
         } 


        closedir(d); 
       } 
       break; 
      case 2: 
       printf("Client has requested a single file. Waiting for file name.\n"); 
        /* block until receive message from a client */ 

       if(recvMsgSize = recv(clntSock, file_request, sizeof(file_request), 0) < 0) 
       { 
        printf("Could not block socket\n"); 
        printf("Failed with the following error: %s\n", strerror(errno)); 
       } 

       printf("Client has request: %s\n", file_request); 

       FILE *fp; 
       fp = fopen(file_request, "r"); 
       if(fp == NULL) 
       { 
        // send message to client that file does not exist 
        printf("Specified file does not exist."); 
       } 

       fseek(fp, 0, SEEK_END); 
       size_t file_size = ftell(fp); 
       fseek(fp, 0, SEEK_SET); 

        if(fread(file, file_size, 1, fp) <= 0) 
       { 
        // send message that unable to copy file to buffer 
        printf("Unable to copy file to buffer"); 
        exit(1); 
        } 

       if (send(clntSock, file, sizeof(file), 0) < 0) 
        { 
        printf("error in sending file"); 
       } 

       bzero(file, sizeof(file)); 
       break; 
      case 3: 
       break; 
      case 4: 
       printf("Client has closed connection. Waiting on new clients"); 
       break; 
     } 
     recvMsgSize = 0; 
     data_recv[0] = 0; 
    } 

    close(servSock); 
} 

Client.c

/*code for client portion of server-client setup*/ 
/*communication occurs overs TCP*/ 

#include <stdio.h>    /* for printf() and fprintf() */ 
#include <sys/socket.h>  /* for socket(), connect(), sendto(), and recvfrom() */ 
#include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */ 
#include <stdlib.h>    /* for atoi() and exit() */ 
#include <string.h>    /* for memset() */ 
#include <unistd.h>    /* for close() */ 
#include <stdbool.h>  /* for boolean values */ 

#define RCVBUFSIZE 255 /* Size of receive buffer */ 

void DieWithError(char *errorMessage); /* Error handling function */ 
char * printMenu(); 

int main(int argc, char *argv[]) 
{ 
    int sock,i,num;     /* Socket descriptor */ 
    struct sockaddr_in echoServAddr; /* Echo server address */ 
    struct sockaddr_in fromAddr;  /* address of data sender */ 
    unsigned short echoServPort;  /* Echo server port */ 
    char *servIP;     /* Server IP address (dotted quad) */ 
    char *echoString;    /* String to send to echo server */ 
    char echoBuffer[RCVBUFSIZE];  /* Buffer for echo string */ 
    unsigned int echoStringLen;  /* Length of string to echo */ 
    int bytesRcvd, totalBytesRcvd; /* Bytes read in single recv() 
             and total bytes read */ 
    char menuOption[1];    /* User Menu seclection to send to server */ 
    char buffer[RCVBUFSIZE+1];  /* Buffer for receiving data from server */ 
    int recvDataLen;     /* Length of received response */ 
    char * menuMsg;   /* used to print menu options */ 
    char * temp[255] = {0}; 
    char file_buffer[2000];  /* file sent by server */ 
    char file_request[50];  /* file requested by client */ 


    if (argc != 3) /* Test for correct number of arguments */ 
    { 
     fprintf(stderr,"Usage: %s <Server IP> [<Port Id>]\n", argv[0]); 
     exit(1); 
    } 

    servIP = argv[1];   /* First arg: server IP address (dotted quad) */ 

    if (argc == 3) 
    { 
     echoServPort = atoi(argv[2]); /* Use given port, if any */ 
    } 
    else 
    { 
    fprintf(stderr,"Usage: %s requires [<Port Id>]\n", argv[0]); 
    } 

    /* Create a reliable, stream socket using TCP */ 
    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 
     DieWithError("socket() failed"); 

    /* Construct the server address structure */ 
    memset(&echoServAddr, 0, sizeof(echoServAddr));  /* Zero out structure */ 
    echoServAddr.sin_family  = AF_INET;    /* Internet address family */ 
    echoServAddr.sin_addr.s_addr = inet_addr(servIP); /* Server IP address */ 
    echoServAddr.sin_port  = htons(echoServPort); /* Server port */ 

    /* Establish the connection to the echo server */ 
    if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) 
     DieWithError("connect() failed"); 

    //echoStringLen = strlen(echoString);   /* Determine input length */ 

    menuMsg = printMenu(); 

    while(atoi(menuOption) != -1){ 
    printf("%s", menuMsg); 
    scanf("%s", &menuOption[0]); 

    switch(atoi(menuOption)){ 
      case 1: 
       /* send menu choice to server indicating client wants list of all files on server */ 
       if (send(sock, menuOption, sizeof(menuOption), 0) < 0){ 
        printf("sendto() sent a different number of bytes than expected"); 
       } 

       printf("\nYou choose to recieve a list of files from the server\n\n"); 
       printf("Below is the returned response from the server:\n"); 

       /* receive a response from the server */ 
       if ((bytesRcvd = recv(sock, buffer, RCVBUFSIZE - 1, 0)) <= 0) 
          DieWithError("recv() failed or connection closed prematurely"); 


       /* null terminate the received data */ 
       buffer[bytesRcvd] = '\0'; 
       printf("%s\n", buffer); /* Print the echoed arg */ 

       break; 
      case 2: 
       /* send menu choice to server indicating client wants list of all files on server */ 
       if (send(sock, menuOption, sizeof(menuOption), 0) < 0){ 
        printf("sendto() sent a different number of bytes than expected"); 
       } 

       printf("You choose to retrieve a single file from the server\n"); 
       printf("What file would you like: "); 
       scanf("%s", &file_request[0]); 

       if (send(sock, file_request, strlen(file_request), 0) < 0) 
       { 
         printf("sendto() sent a different number of bytes than expected"); 
       } 

       /* Recv a response */ 
        bytesRcvd = sizeof(fromAddr); 
       if (recvDataLen = recv(sock, buffer, sizeof(buffer), 0) < 0) 
       { 
         printf("recvfrom() failed\n"); 
       } 

       char new_file[] = "copied"; 
       strcat(new_file, buffer); 
       FILE *fp; 
       fp = fopen(new_file, "w+"); 

       if(fwrite(buffer, 1, sizeof(buffer), fp) < 0) 
       { 
        printf("error writting file\n"); 
        exit(1); 
       } 
       break; 
      case 3: 
        printf("You choose to retrieve all files from the server\n"); 
       break; 
      case 4: 
       /* send menu choice to server indicating client wants list of all files on server */ 
       if (send(sock, menuOption, sizeof(menuOption), 0) < 0){ 
        printf("sendto() sent a different number of bytes than expected"); 
       } 

       printf("Closing connection\n"); 
       close(sock); 
       exit(0); 
      default: 
       printf("You picked an invalid option. Try again.\n"); 
       break; 
     } 

    } 

    printf("\n"); /* Print a final linefeed */ 

    close(sock); 
    exit(0); 
} 


char * printMenu() 
{ 
    static char message[250] = "Select an option from below:\n"; 
     strcat(message, "(1) List all files on server\n"); 
    strcat(message, "(2) Retrieve file from server\n"); 
    strcat(message, "(3) Retrieve all files from server\n"); 
    strcat(message, "(4) Close Connection\n"); 
    strcat(message, "Enter your selection: "); 
    return message; 
} 
+0

一般來說,「......並在最後的垃圾......」是調試-C-說話‘的思維走你的代碼,看看,如果你不知何故失蹤疑串建立一個空結尾。’它的'char menuOption [1]'應該保存一個C字符串,沒有* content *的空間(記住,字符串需要一個終止符,並且這個數組有空間)。 – WhozCraig 2014-10-17 14:59:33

+0

仔細檢查並解決空終止問題。這樣做時,請注意,例如,當一端發送「message \ 0」(並且是,即八個字符,而不是strlen(「message」))時,對等方的成功recv()調用可能會返回8個字符,或1個字符,或其中任何一個字符。除非你明白,str​​len(),strcat(),printf(%s ..)等調用很可能會失敗。 – 2014-10-17 16:57:46

回答

2

你是不是發送空終止到服務器。

if (send(sock, file_request, strlen(file_request), 0) < 0) 
{ 
    printf("sendto() sent a different number of bytes than expected"); 
} 

strlen不計算空終止符的長度。

替換它strlen(file_request) + 1

我的意思不是說是一個完美的解決方案,只是一種指向你的錯誤。

+0

我知道它是來自標題的printf(%s ..)的strlen()。 – 2014-10-17 16:39:48

+0

還有至少一個'strcat(new_file,buffer);'當「緩衝區」包含以空字符結尾的字符串時,一點也​​不確定。 – 2014-10-17 16:50:18