2016-08-23 4 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 Steven:

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; 

имен, которые, как заблуждение. Имя почти никогда не является целым числом. Для размеров ввода/вывода просто используйте одно простое имя, например n, len или size. Даже если вы не заботитесь о себе, вы хотите заботиться, прежде чем публиковать свой вопрос на открытом форуме. В противном случае, когда люди видят

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

они могут думать send некоторая другая функция отправить (2), или о том, что человек, задающий вопрос был неосторожен.

+1

Он вызывает 'perror()' большую часть времени, что является адекватным. Вы здесь не определились. – EJP

+0

А что такое ** актуальная ** проблема? – Olaf

+0

@Olaf Актуальная проблема в вопросе. Дело в том, что его второй 'recv()' блокирует, и этот ответ вообще не обратился к нему. – EJP

1

Основная проблема, которую я вижу, заключается в том, что ни клиент, ни сервер не обрабатывают входы/выходы сокета в целом. Они не обрабатывают случаи, когда чтение и запись передают меньшее количество байтов, которые затем запрашиваются, вам необходимо зацикливать ввод-вывод. И клиент все равно читает слишком много байтов с сервера, поэтому ваш второй recv() блокирует. И вы полагаетесь на разъединение, чтобы указать, что конец файла достигнут, но это не позволяет клиенту выполнить соответствующую проверку ошибок, чтобы узнать, действительно ли был получен полный файл или нет.

Кроме того, при отправке содержимого файла сервер пытается прочитать весь файл в памяти (плохой!), Не выполняя надлежащую проверку ошибок в файле ввода/вывода и обрабатывает содержимое файла как текст вместо двоичного (не используйте 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; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^