2016-08-23 3 views
0

Das ist mein Client-Programm, das Dateien vom Server anfordert:Zweite recv Aufruf keine Daten empfangen, stoppt die Ausführung in 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; 
} 

Das ist mein Server-Programm, das Ersuchen um Dateien vom Client akzeptiert:

#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); 
    } 

Das Problem ist, dass in dem Client, mein zweiter recv() Anruf, wo es sollte den Inhalt einer Datei erhalten, nichts zeigt. Die Programme bleiben an diesem Punkt stehen, aber die Serverprogramme zeigen an, dass sie den Dateiinhalt gesendet haben. Der Client erhält es nicht.

+0

überprüft Wireshark, um zu sehen, ob die Daten es auf die Leitung macht? – yano

+1

Dies ist nicht lesbar! Format & Einzug dieses Chaos zuerst. – Olaf

+0

Bitte formatieren Sie dieses unlesbare Chaos richtig. – EJP

Antwort

2

Das grundlegende Problem ist, dass Sie nicht die Rückgabewerte überprüft, um zu sehen, wie viele Daten Sie tatsächlich gesendet und empfangen werden.Also, wenn der Client ruft:

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

wird es erhalten bis zu sizeof(msg) (512) Bytes, die wahrscheinlich sowohl die OK Nachricht des Server gesendet wird, und der Dateiinhalt (nach dem NUL). Das heißt, wenn es einen zweiten recv Aufruf ausführt, um den Inhalt abzurufen, blockiert es, da es bereits den Inhalt des ersten Aufrufs liest und keine weiteren Daten im Empfangspuffer warten.

1

Ihre Fehlerprüfung ist willkürlich, und folglich verpassen Sie sicherlich ein Problem, das vor dem Verhalten auftritt, das Sie beobachten. Ich empfehle Ihnen, RW Steven Idiom zu folgen:

Testen Sie jeden Funktionsaufruf, und behandeln Sie jeden Fehler. Bei einfachen Programmen rufen Sie einfach err (3) bei einem Fehler auf. Tun Sie das konsequent, und das Verhalten des Programms wird viel weniger mysteriös sein (wenn immer noch gelegentlich überraschend). Und fürchte dich nicht vor der Leertaste! Es ist leicht zu treffen und einfacher zu lesen.

Meine andere guter Rat, wenn ich darf, betrifft

int send_file_name,rec_msg; 

Namen wie die verwirrend sind. Ein Name ist fast nie eine ganze Zahl. Verwenden Sie für E/A-Größen nur einen einfachen Namen wie n, len oder size. Selbst wenn Sie sich selbst nicht interessieren, sollten Sie sich vor der Veröffentlichung Ihrer Frage in einem offenen Forum darum kümmern. Andernfalls, wenn die Leute sehen

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

sie denken kann send einige andere Funktion als ist senden (2), oder dass die Person, die Frage zu stellen war unvorsichtig.

+1

Er ruft 'perror()' die meiste Zeit, was angemessen ist. Sie haben das eigentliche Problem hier nicht identifiziert. – EJP

+0

Und was ist das ** tatsächliche ** Problem? – Olaf

+0

@Olaf Das eigentliche Problem ist in der Frage angegeben. Es ist, dass sein zweites 'recv()' blockt, und diese Antwort hat es überhaupt nicht angesprochen. – EJP

1

Das Hauptproblem, das ich sehe, ist, dass weder der Client noch der Server Socket-I/O im Allgemeinen korrekt behandeln. Sie behandeln nicht die Fälle, in denen Lese- und Schreibvorgänge weniger Bytes übertragen als angefordert werden, Sie müssen die E/A-Schleife durchführen. Und der Client liest sowieso zu viele Bytes vom Server, weshalb Ihre zweite recv() blockiert. Und Sie verlassen sich auf eine Trennung, um anzuzeigen, dass das Ende der Datei erreicht wurde, aber das erlaubt dem Client keine angemessene Fehlerprüfung, um zu wissen, ob die vollständige Datei tatsächlich empfangen wurde oder nicht.

Wenn der Inhalt einer Datei gesendet wird, versucht der Server außerdem, die gesamte Datei in den Speicher (schlecht!) Zu lesen, keine angemessene Fehlerprüfung für die Datei-E/A durchzuführen und behandelt den Dateiinhalt als Text statt als binär (verwenden Sie nicht strlen() auf binäre Daten!).

etwas ähnlich stattdessen versuchen:

#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; 
} 
Verwandte Themen