2016-08-23 30 views
0

執行這是從服務器請求文件,我的客戶端程序:二recv調用不接收數據,暫停用C

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

#define SERVER_PORT 5959 
#define MAX_LINE 512 

void setstring(char *str){ 
    str[MAX_LINE-1]='\0'; 
} 

int main(int argc, char * argv[]){ 
    FILE *fp; 
    struct hostent *hp; 
    struct sockaddr_in sin; 
    char *host; 
    char filename[MAX_LINE],buf[MAX_LINE],reply[MAX_LINE],rec_line[MAX_LINE]; 
    int s; 
    char msg[MAX_LINE]; 
    int len,new_len,rec_file; 
    if (argc==2) { 
     host = argv[1]; 
    } 
    else { 
     fprintf(stderr, "usage: simplex-talk host\n"); 
     exit(1); 
    } 

    /* translate host name into peer's IP address */ 
    hp = gethostbyname(host); 
    if (!hp) { 
     fprintf(stderr, "simplex-talk: unknown host: %s\n", host); 
     exit(1); 
    } 
    else 
     printf("Client's remote host: %s\n", argv[1]); 

    /* build address data structure */ 
    bzero((char *)&sin, sizeof(sin)); 
    sin.sin_family = AF_INET; 
    bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 
    sin.sin_port = htons(SERVER_PORT); 

    /* active open */ 
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { 
     perror("simplex-talk: socket"); 
     exit(1); 
    } 
    else 
     printf("Client created socket.\n"); 

    int send_file_name,rec_msg; 
    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) 
    { 
     perror("simplex-talk: connect"); 
     close(s); 
     exit(1); 
    } 
    else{ 
     printf("Client connected.\n"); 
     /* main loop: get and send lines of text */ 
    printf("Hello from server\n"); 
    while(!(strcmp(reply,"bye")==0)){ 
      printf("Enter the file name:\n"); 
      scanf("%s",filename); 
      setstring(filename); 
      send_file_name=send(s,filename,strlen(filename)+1,0); 
      if(send_file_name<0) 
       fputs("Error sending filename",stdout); 
      rec_msg=recv(s,msg,sizeof(msg),0); 
      if(strcmp(msg,"File not found")==0) 
       printf("File not found\n"); 
      else{ 
       printf("%s\n",msg); 
       fp=fopen(filename,"w"); 
       printf("CP1\n"); 
       if(rec_file=recv(s,rec_line,sizeof(rec_line),0)>0){ 
        printf("CP2"); 
        printf("String recieved:%s\n",rec_line); 
        if(len=fwrite(rec_line,1,rec_file+1,fp)>0) 
         printf("Recieved file\n"); 
        else 
         printf("Error writing to file\n"); 
       } 
       else 
        printf("Not recieved\n"); 
      } 
      printf("Enter 'bye' to terminate requesting files\n"); 
      scanf("%s",reply); 
     } 
    } 
    return 0; 
} 

這是接受來自客戶端的請求文件,我的服務器程序:

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

#define SERVER_PORT 5959 
#define MAX_PENDING 5 
#define MAX_LINE 256 

void setstring(char* str){ 
    str[MAX_LINE-1]='\0'; 
} 

int main(){ 
    FILE *fp; 
    struct sockaddr_in sin; 
    char buf[MAX_LINE],msg[MAX_LINE],*rec_line; 
    int len; 
    int s, new_s,count; 
    char str[INET_ADDRSTRLEN]; 
    int error_file,send_msg,read_line,send_file; 

    bzero((char *)&sin, sizeof(sin)); 
    sin.sin_family = AF_INET; 
    sin.sin_addr.s_addr = inet_addr("0.0.0.0"); 
    sin.sin_port = htons(SERVER_PORT); 

    /* setup passive open */ 
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { 
     perror("simplex-talk: socket"); 
     exit(1); 
    } 

    inet_ntop(AF_INET, &(sin.sin_addr), str, INET_ADDRSTRLEN); 
    printf("Server is using address %s and port %d.\n", str, SERVER_PORT); 

    if ((bind(s, (struct sockaddr *)&sin, sizeof(sin))) < 0) { 
     perror("simplex-talk: bind"); 
     exit(1); 
    } 
    else 
     printf("Server bind done.\n"); 

    listen(s, MAX_PENDING); 
    /* wait for connection, then receive and print text */ 
    while(1) { 
     if ((new_s = accept(s, (struct sockaddr *)&sin, &len)) < 0) { 
      perror("simplex-talk: accept"); 
      exit(1); 
     } 

     printf("Server Listening.\n"); 
     printf("Greetings\n"); 
     int rec_file_name=recv(new_s,buf,sizeof(buf),0); 
     if(rec_file_name>0) 
      printf("File requested:%s\n",buf); 
      fp=fopen(buf,"r"); 
      if(fp==NULL) 
      { 
       fputs("File not found\n",stdout); 
       strcpy(buf,"File not found"); 
       if(error_file=send(new_s,buf,strlen(buf)+1,0)>0) 
        fputs("Successfully send error message to client\n",stdout); 
      } 
      else{ 
       bzero(buf,MAX_LINE); 
       printf("File found :) \n"); 
       strcpy(buf,"OK"); 
       if(send_msg=send(new_s,buf,strlen(buf)+1,0)>0) 
        fputs("File found message sent to client\n",stdout); 

       fseek(fp,0,SEEK_END); 
       int file_size=ftell(fp); 
       fseek(fp,0,SEEK_SET); 
       printf("File size:%d\n",file_size); 
       rec_line=(char *)malloc(sizeof(char)*(file_size)); 
       read_line=fread(rec_line,1,file_size+1,fp); 
       printf("File read: %s\n",rec_line); 

       if(send_file=send(new_s,rec_line,strlen(rec_line)+1,0)>0) 
        printf("File string sent to client\n"); 
      } 
     } 

     close(new_s); 
    } 

的問題是,在客戶端,我的第二個recv()通話,這樣它應該接收文件的內容,顯示什麼。程序暫時停止,但服務器程序顯示它已發送文件內容。客戶端沒有收到它。

+0

檢查Wireshark以查看數據是否使其連接到電線? – yano

+1

這是不可讀的!先格式化並縮小這個混亂。 – Olaf

+0

請正確格式化這個難以辨認的混亂。 – EJP

回答

2

最根本的問題是,你不檢查返回值,看看你實際上有多少數據發送和接收。因此,當客戶端調用:

rec_msg=recv(s,msg,sizeof(msg),0); 

也將獲得高達sizeof(msg)(512)個字節,這可能是兩者的OK消息服務器發送和文件內容(NUL後)。這意味着當它調用第二個recv來獲取內容時,它會阻塞,因爲它已經在第一次調用中讀取了內容,並且在接收緩衝區中沒有更多的數據在等待。

1

您的錯誤檢查是雜亂無章的,因此您肯定會錯過在您觀察行爲之前發生的問題。我建議您按照RW史蒂芬的成語:

int n; 
if((n = recv(new_s, buf, sizeof(buf), 0)) < 0) { 
    err(EXIT_FAILURE, "recv %d", __LINE__); 
} 

測試每個函數調用,並處理每一個錯誤。對於簡單的程序,只需致電err(3)即可。一直這樣做,程序的行爲將不那麼神祕(如果偶爾還會令人驚訝)。不要害怕太空吧!這很容易打,更容易閱讀。

我的建議的其他一點,如果可以的話,涉及

int send_file_name,rec_msg; 

的名字,像易混淆。名稱幾乎不是整數。對於I/O大小,只需使用一個簡單的名稱,如n,lensize。即使你不關心自己,在開放論壇上發佈你的問題之前,你也要關心。否則,當人們看到

send_file_name=send(s,filename,strlen(filename)+1,0); 

他們可能認爲send一些功能比其它發送(2),或問問題的人是不小心。

+1

他大部分時間都在調用perror(),這已經足夠了。您尚未在此處確定實際問題。 – EJP

+0

什麼是**實際**問題? – Olaf

+0

@Olaf問題中提到了實際問題。這是他的第二個'recv()'被阻塞了,這個答案根本沒有解決它。 – EJP

1

我看到的主要問題是客戶端和服務器都無法正確處理套接字I/O。他們沒有處理讀取和寫入傳輸的字節數較少的情況,因此您需要循環I/O。客戶端無論如何都會從服務器讀取太多的字節,這就是爲什麼您的第二個recv()被阻止。並且您依靠斷開連接來指示已達到文件末尾,但這不允許客戶端進行足夠的錯誤檢查以確定是否實際收到完整文件。另外,發送文件內容時,服務器試圖將整個文件讀入內存(壞!),對文件I/O沒有做足夠的錯誤檢查,並且將文件內容視爲文本而不是二進制文件(不要在二進制數據上使用strlen()!)。

嘗試一些更喜歡這個:

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

#define SERVER_PORT 5959 
#define MAX_LINE 512 

int sendstring(int sock, const char *str) { 
    if (!str) str = ""; 
    int len = strlen(str) + 1; 

    do { 
     int ret = send(sock, str, len, 0); 
     if (ret <= 0) return -1; 
     str += ret; 
     len -= ret; 
    } 
    while (len > 0); 

    return 0; 
} 

int readbuf(int sock, void *buf, int buflen) { 
    char *pbuf = (char*) buf; 

    while (buflen > 0) { 
     int len = recv(sock, pbuf, buflen, 0); 
     if (len <= 0) return -1; 
     pbuf += len; 
     buflen -= len; 
    } 

    return 0; 
} 

int readstring(int sock, char *str, int maxlen) { 
    while (maxlen > 0) { 
     if (recv(sock, str, 1, 0) <= 0) return -1; 
     if (*str == '\0') return 0; 
     ++str; 
     --maxlen; 
    } 
    return -2; 
} 

int readfile(int sock, int fd) { 
    int filesize; 
    char buf[MAX_LINE]; 

    if (readbuf(sock, &filesize, sizeof(filesize)) < 0) return -1; 
    filesize = ntohl(filesize); 

    while (filesize > 0) { 
     int len = readbuf(sock, buf, min(sizeof(buf), filesize)); 
     if (len < 0) return -1; 
     if (fwrite(buf, len, 1, fp) != 1) return -2; 
     filesize -= len; 
    } 

    return 0; 
} 

int main(int argc, char * argv[]) { 
    char filename[MAX_LINE], reply[MAX_LINE]; 

    if (argc != 2) { 
     fprintf(stderr, "usage: simplex-talk host\n"); 
     exit(1); 
    } 

    char *host = argv[1]; 

    /* translate host name into peer's IP address */ 
    struct hostent *hp = gethostbyname(host); 
    if (!hp) { 
     fprintf(stderr, "simplex-talk: unknown host: %s\n", host); 
     exit(1); 
    } 

    if (hp->h_addrtype != AF_INET) { 
     fprintf(stderr, "simplex-talk: unsupported address type %d for host: %s\n", hp->h_addrtype, host); 
     exit(1); 
    } 

    /* build address data structure */ 
    struct sockaddr_in sin; 
    bzero((char *)&sin, sizeof(sin)); 
    sin.sin_family = AF_INET; 
    bcopy(hp->h_addr, &sin.sin_addr, hp->h_length); 
    sin.sin_port = htons(SERVER_PORT); 

    printf("Host's remote IP: %s\n", inet_ntoa(&sin.sin_addr)); 

    /* active open */ 
    int s = socket(PF_INET, SOCK_STREAM, 0); 
    if (s < 0) { 
     perror("simplex-talk: socket"); 
     exit(1); 
    } 

    printf("Client created socket.\n"); 

    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) 
    { 
     perror("simplex-talk: connect"); 
     close(s); 
     exit(1); 
    } 

    printf("Client connected.\n"); 

    /* main loop: get and send lines of text */ 
    do { 
     printf("Enter the file name ('bye' to quit):\n"); 

     if (scanf("%512s", filename) != 1) { 
      printf("Error reading filename\n"); 
      break; 
     } 

     if (strcmp(filename, "bye") == 0) { 
      sendstring(s, "bye"); 
      break; 
     } 

     if (sendstring(s, filename) < 0) { 
      printf("Error sending filename\n"); 
      break; 
     } 

     if (readstring(s, reply, sizeof(reply)) < 0) { 
      printf("Error reading reply\n"); 
      break; 
     } 

     if (strcmp(reply, "OK") != 0) { 
      printf("%s\n", reply); 
      if (strcmp(reply, "bye") == 0) break; 
      continue; 
     } 

     FILE *fp = fopen(filename, "wb"); 
     if (!fp) { 
      printf("Error opening file\n"); 
      break; 
     } 

     printf("Receiving file\n"); 

     int ret = readfile(s, fd); 
     fclose(fp); 

     if (ret < 0) { 
      if (ret == -2) 
       printf("Error writing file\n"); 
      else 
       printf("Error reading file\n"); 

      break; 
     } 

     printf("Received file\n"); 
    } 
    while (1); 

    close(s); 
    return 0; 
} 

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

#define SERVER_PORT 5959 
#define MAX_PENDING 5 
#define MAX_LINE 512 

int sendbuf(int sock, void *buf, int buflen) { 
    char *pbuf = (char*) buf; 

    while (len > 0) { 
     int len = send(sock, pbuf, buflen, 0); 
     if (len <= 0) return -1; 
     pbuf += len; 
     buflen -= len; 
    } 

    return 0; 
} 

int sendstring(int sock, const char *str) { 
    if (!str) str = ""; 
    return sendbuf(sock, str, strlen(str) + 1); 
} 

int sendfile(int sock, int fd) { 
    char buf[MAX_LINE]; 

    struct stat s; 
    if (fstat(fd, &s) < 0) return -2; 

    int pos = ftell(fp); 
    if (pos == -1) return -2; 

    int file_size = s.st_size - pos; 
    int tmp_file_size = htonl(file_size); 
    if (sendbuf(sock, &tmp_file_size, sizeof(tmp_file_size)) < 0) return -1; 

    while (file_size > 0) { 
     int len = fread(buf, 1, min(sizeof(buf), file_size), fp); 
     if (len < 1) return -2; 
     if (sendbuf(sock, buf, len) < 0) return -1; 
     file_size -= len; 
    } 

    return 0; 
} 

int readstring(int sock, char *str, int maxlen) { 
    while (maxlen > 0) { 
     if (recv(sock, str, 1, 0) <= 0) return -1; 
     if (*str == '\0') return 0; 
     ++str; 
     --maxlen; 
    } 
    return -2; 
} 

int main() { 
    char msg[MAX_LINE]; 

    struct sockaddr_in sin; 
    bzero((char *)&sin, sizeof(sin)); 
    sin.sin_family = AF_INET; 
    sin.sin_addr.s_addr = INADDR_ANY; 
    sin.sin_port = htons(SERVER_PORT); 

    /* setup passive open */ 
    int s = socket(PF_INET, SOCK_STREAM, 0); 
    if (s < 0) { 
     perror("simplex-talk: socket"); 
     exit(1); 
    } 

    printf("Server is using address %s and port %d.\n", inet_ntoa(&(sin.sin_addr)), SERVER_PORT); 

    if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 
     perror("simplex-talk: bind"); 
     close(s); 
     exit(1); 
    } 

    printf("Server bind done.\n"); 

    if (listen(s, MAX_PENDING) < 0) { 
     perror("simplex-talk: listen"); 
     close(s); 
     exit(1); 
    } 

    printf("Server Listening.\n"); 

    /* wait for connection, then receive and print text */ 
    do { 
     int len = sizeof(sin); 
     int cli_s = accept(s, (struct sockaddr *)&sin, &len); 
     if (cli_s < 0) { 
      perror("simplex-talk: accept"); 
      close(s); 
      exit(1); 
     } 

     printf("Client connected\n"); 

     do { 
      if (readstring(cli_s, msg, sizeof(msg)) < 0) { 
       printf("Error reading request\n"); 
       break; 
      } 

      if (strcmp(msg, "bye") == 0) break; 

      printf("File requested: %s\n", msg); 

      FILE *fp = fopen(msg, "rb"); 
      if (!fp) 
      { 
       printf("Cannot open file\n"); 
       if (sendstring(cli_s, "Cannot open file") < 0) { 
        printf("Error sending reply\n"); 
        break; 
       } 
       continue; 
      } 

      printf("File found :) \n"); 

      if (sendstring(cli_s, "OK") < 0) { 
       printf("Error sending reply\n"); 
       fclose(fp); 
       break; 
      } 

      ret = sendfile(cli_s, fp); 
      fclose(fp); 

      if (ret < 0) { 
       printf("Error sending file\n"); 
       break; 
      } 

      printf("File sent to client\n"); 
     } 
     while (1); 

     close(cli_s); 
    } 
    while (1); 

    close(s); 
    return 0; 
} 
相關問題