C程序文件传输,在客户端打印出服务器端错误

时间:2017-10-10 22:03:10

标签: c networking server client

我正在创建一个程序,该程序从服务器请求文件并发回文件,创建新文件并将该文件的内容写入新文件。除了服务器端错误消息(即文件不存在)应该在客户端打印时,一切都工作正常。谁能给我一个如何完成这个的线索?我是C的新手,但愿意了解更多。我的主要问题是,如果我直接发送消息,客户端不知道它是一个错误,并且将完成并创建一个文件并将消息写入该文件。我以为我需要发回-1,所以当客户端调用recv时,它会返回-1作为长度并打印一条消息。

这是我的客户:

  ssize_t recvx(int sockfd, void *buf, size_t len) {
    int var = recv(sockfd, buf, len, 0);
    if(var != -1)
    {
      return var;
    } else {
      printf("%s \n","Did not receive.");
      exit(1);
    }
  }

  int main(int argc, char *argv[])
  {
    char buf[MAX_LINE];
    struct addrinfo hints;
    struct addrinfo *rp, *result;
    int bytes_received;
    int s;
    char *server;
    char *port;
    char *file;
    int fd = -1; //file descriptor
    int bytes_written;

    if (argc==4)
    {
      server = argv[1];
      port = argv[2];
      file = argv[3];
    }
    else
    {
      fprintf(stderr, "invalid # of arguments\n");
      exit(1);
    }

    /* Translate host name into peer's IP address */
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = 0;
    hints.ai_protocol = 0;

    if ((s = getaddrinfo(server, port, &hints, &result)) != 0 )
    {
      fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
      exit(1);
    }

    /* Iterate through the address list and try to connect */
    for (rp = result; rp != NULL; rp = rp->ai_next)
    {
      if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
      {
        continue;
      }
      if (connect(s, rp->ai_addr, rp->ai_addrlen) != -1)
 {
        break;
      }
      close(s);
    }

    if (rp == NULL)
    {
      perror("stream-talk-client: connect");
      exit(1);
    }
    freeaddrinfo(result); 
    /*send lines of text */ 
   send(s, file, sizeof(file), 0);


   while(bytes_received != 0)
    {
      bytes_received = recvx(s, buf, 20);
      if(bytes_received == -1)
      {
        fprintf(stderr, "Client Error: Error receiving file \n");
        exit(1);
      } else {
        if(fd == -1)
        {
          fd = open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
          if(fd == -1)
          {
           fprintf(stderr,"Client Error: Open failed \n");
           exit(1);
         }
         bytes_written = write(fd,buf,bytes_received);
         if(bytes_written == -1)
         {
           fprintf(stderr,"%s \n", "Client Error: Write error");
           exit(1);
         }
       } else {
         bytes_written = write(fd,buf,bytes_received);
         if(bytes_written == -1)
         {
           fprintf(stderr,"%s \n", "Client Error: Write error");
           exit(1);
         }
       }
     }
   }
   if(close(fd) != 0)
   {
     printf("%s \n", "Client Error: File did not close successfully");
     exit(1);
   }


   close(s);

   return 0;
 }  

这是我的服务器:

int main(int argc, char *argv[])
  {
    struct addrinfo hints;
    struct addrinfo *rp, *result;
    char filename[MAX_LINE];
    int s, new_s;
    int bytes_transferred;
    int fd; //file descriptor
    struct stat statBuffer; //to hold file info
    off_t offset = 0;

    /* Build address data structure */
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;
    hints.ai_protocol = 0;
    hints.ai_canonname = NULL;
    hints.ai_addr = NULL;
    hints.ai_next = NULL;

    /* Get local address info */
    if ((s = getaddrinfo(NULL, argv[1], &hints, &result)) != 0 )
    {
      fprintf(stderr, "%s: getaddrinfo: %s\n", argv[0], gai_strerror(s));
      exit(1);
    }

    /* Iterate through the address list and try to perform passive open */
    for (rp = result; rp != NULL; rp = rp->ai_next)
    {
      if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1 )
      {
        continue;
      }

      if (!bind(s, rp->ai_addr, rp->ai_addrlen))
      {
        break;
      }
      close(s);
    }
    if (rp == NULL)
    {
      perror("stream-talk-server: bind");
      exit(1);
    }
    if (listen(s, MAX_PENDING) == -1)
    {
      perror("stream-talk-server: listen");
      close(s);
      exit(1);
    }

    freeaddrinfo(result);

    /* Wait for connection, then receive and print text */
    while(1)
     { 
      if ((new_s = accept(s, rp->ai_addr, &(rp->ai_addrlen))) < 0)
      {
        perror("stream-talk-server: accept");
        close(s);
        exit(1);
      }
      while(bytes_transferred == recv(new_s,filename,sizeof(filename),0))
      {
        if(bytes_transferred == -1)
        {
          fprintf(stderr, "Server Error: Error receiving filename \n");
          exit(1);
        }
      }
      printf("%s \n", filename);
      fd =open(filename,O_RDONLY);

      if(fd < 0)
      {
        fprintf(stderr,"Server Error: file doesn't exist\n");
        exit(1);
     }
     else
     {
       printf("%s \n","file opened successfully");
     }
     /*get info from file descriptor (fd) and store it in statBuffer struct */
     fstat(fd, &statBuffer);
     bytes_transferred = sendfile(new_s,fd,&offset,statBuffer.st_size);
     if(bytes_transferred == -1)
     {
       fprintf(stderr, "Server Error: File not transferred successfully");
     }
     else
     {
       printf("%s \n", "File transferred successfully");
     }
     if(close(fd) != 0)
     {
       fprintf(stderr, "Server Error: File not close successfully");
     }
     else{
       break;
     }
   }
   close(new_s);

   return 0;
 }

1 个答案:

答案 0 :(得分:0)

基本上你正在实施的是HTTP和FTP服务器所做的事情。两者都有特定但相当不同的协议步骤来处理错误。 HTTP情况很容易理解 - 服务器不会发回文件:它会发回一堆标题,然后是文件。客户端可以检查标头以了解是否有任何文件数据要遵循。

在一个非常简单的例子中,我怀疑你可以在代码中实现类似的东西而不需要太多的工作 - 只需让服务器在文件的其余部分之前发送一个单字节的响应代码。您可以使用0(例如)来指示有效文件,以及其他数字以指示特定的错误条件。客户端只会像当前一样读取数据,但如果第一个字节不为零,则它知道后面没有任何其他内容(如果有的话)是有效的。

或者您可以安排,如果第一个字节不为零,则后面的文本不是预期的文件,而是一条错误消息,应该由客户端显示。

你可以根据自己的喜好来扩展这样的方案,直到最终得到HTTP:)