[使用Fork()的C中的TCP并发客户端/服务器

问题描述 投票:0回答:1

我使用fork()在C套接字编程中并发了tcp文件传输客户端/服务器。该程序应该执行以下操作:客户端应连接到服务器并要求输入txt。它将与文件一起存储,服务器将查找并发送txt。文件发送到客户端,然后将其存储在本地。这是针对一个大学的项目的,我得到的反馈是我的服务器代码中的Use fork是不正确的,并且它不应该工作,但是我的程序可以正常工作吗?我对fork()的使用是否错误?另外,当我的客户端连接到服务器时,为什么它连接到随机端口而不是8888,如下所示。

enter image description here

服务器:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

#define SIZE 1024

void send_file(FILE *fp, int sockfd){
  int n;
  char data[SIZE] = {0};

  while(fgets(data, SIZE, fp) != NULL) {
    if (send(sockfd, data, sizeof(data), 0) < 0) {
      perror("[-]Error in sending file.");
      exit(1);
    }
    bzero(data, SIZE);
  }
  return;
}

int main(){
  // ip address and port
  char *ip = "127.0.0.1";
  int port  = 8888;

  // variables and structures
  int e;
  int sockfd, new_sock;
  struct sockaddr_in server_addr, new_addr;
  socklen_t addr_size;
  char buffer[SIZE];
  pid_t childpid;

  FILE *fp;
  char *filepath;

  // 1. creating the socket
  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if(sockfd < 0){
    perror("[-]Error in socket");
    exit(1);
  }
  printf("[+]Server socket created.\n");

  // 2. writing the data in the structure
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = inet_addr(ip);
  server_addr.sin_port = port;

  // 3. binding the ip address with the port
  addr_size = sizeof(server_addr);
  e = bind(sockfd, (struct sockaddr*)&server_addr, addr_size);
  if (e < 0){
    perror("[-]Error in bind");
    exit(1);
  }
  printf("[+]Binding successfull.\n");

  // 4. listening to the clients
  e = listen(sockfd, 10);
  if (e < 0) {
    perror("[-]Error in listen");
    exit(1);
  }
  printf("[+]Listening...\n");

  // 5. accepting the client connection.

  while (1){
    addr_size = sizeof(new_addr);
    new_sock = accept(sockfd, (struct sockaddr*)&new_addr, &addr_size);
    if (new_sock < 0){
      perror("[-]Error in accpet");
      exit(1);
    }
    printf("Connection accepted from %s:%d\n", inet_ntoa(new_addr.sin_addr), ntohs(new_addr.sin_port));

    childpid = fork();
    if (childpid == 0){
      close(sockfd);

      while(1){
        recv(new_sock, buffer, SIZE, 0);

        if (strcmp(buffer, "LIST") == 0){
          // send the list of filenames.
          bzero(buffer, SIZE);
          strcpy(buffer, "data.txt\nhello.txt");
          send(new_sock, buffer, SIZE, 0);
          bzero(buffer, SIZE);
        }

        else if (strcmp(buffer, "QUIT") == 0){
          // connection disconnected.
          printf("Connection disconnected from %s:%d\n", inet_ntoa(new_addr.sin_addr), ntohs(new_addr.sin_port));
          break;
        }

        else {
          // received the filename, send the file data.
          if (strcmp(buffer, "data.txt") == 0){
            filepath = "server_files/data.txt";
            fp = fopen(filepath, "r");
            send_file(fp, new_sock);
          }

          else if (strcmp(buffer, "hello.txt") == 0) {
            filepath = "server_files/hello.txt";
            fp = fopen(filepath, "r");
            send_file(fp, new_sock);
          }

          bzero(buffer, SIZE);
          send(new_sock, "\0", 1, 0);
          bzero(buffer, SIZE);
        }

      }
    }

  }

}

客户

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

#define SIZE 1024

void remove_char(char *s, int c){
  /* This function is used to remove a character from the character array. */
  int j, n = strlen(s);
  for (int i=j=0; i<n; i++)
    if (s[i] != c){
      s[j++] = s[i];
    }
    s[j] = '\0';
}

void write_file(char *filepath, int sockfd){
  int n;
  FILE *fp;
  char buffer[SIZE];

  fp = fopen(filepath, "w");
  if (fp == NULL) {
    perror("[-]Error in creating file");
    exit(1);
  }

  while (1) {
    n = recv(sockfd, buffer, SIZE, 0);
    if (n == 1) {
      break;
      return;
    }

    fprintf(fp, "%s", buffer);
    fflush(fp);
    bzero(buffer, SIZE);
  }
  return;
}

int main(){
  // ip address and port
  char *ip = "127.0.0.1";
  int port = 8888;

  // variables and structures,
  int e;
  int sockfd;
  struct sockaddr_in server_addr;
  char buffer[SIZE];
  char *filepath;

  // 1. creating the socket
  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if(sockfd < 0){
    perror("[-]Error in socket");
    exit(1);
  }
  printf("[+]Client socket created.\n");

  // 2. writing the data in the structure
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = inet_addr(ip);
  server_addr.sin_port = port;

  // 3. connect to the server
  e = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
  if(sockfd < 0){
    perror("[-]Error in connect");
    exit(1);
  }
  printf("[+]Connected to the server\n");

  printf("\n");
  printf("List of the commands.\n");
  printf("LIST - list all the files.\n");
  printf("LOAD - download the file.\n");
  printf("       LOAD <path>\n");
  printf("QUIT - disconnect from the server.\n");

  while(1){
    fflush(stdout);
    printf("> ");
    fgets(buffer, SIZE, stdin);

    if (strlen(buffer) > 1){
      char *token1 = strtok(buffer, " ");
      char *token2 = strtok(NULL, " ");
      remove_char(token1, '\n');

      if (strcmp(token1, "LIST") == 0) {
        // list all the file of the server.
        send(sockfd, buffer, SIZE, 0);
        recv(sockfd, buffer, SIZE, 0);
        printf("%s\n", buffer);
      }

      else if (strcmp(token1, "LOAD") == 0) {
        if (token2 == NULL) {
          printf("[-]Specify the correct filename.\n");
        } else {
          // save the data of the file received from the server.
          remove_char(token2, '\n');
          send(sockfd, token2, SIZE, 0);

          if (strcmp(token2, "data.txt") == 0){
            filepath = "client_files/data.txt";
            write_file(filepath, sockfd);
            printf("[+]File saved.\n");
          }

          else if (strcmp(token2, "hello.txt") == 0) {
            filepath = "client_files/hello.txt";
            write_file(filepath, sockfd);
            printf("[+]File saved.\n");
          }

          else {
            printf("Incorrect path\n");
          }
        }
      }

      else if (strcmp(token1, "QUIT") == 0) {
        // disconnect from the server.
        printf("[+]Disconnected from the server.\n");
        send(sockfd, token1, SIZE, 0);
        break;
      }

      else {
        printf("[-]Invalid command\n");
      }
    }

    bzero(buffer, SIZE);
  }

}
c sockets client-server tcpclient
1个回答
0
投票

您有几个问题:

-Don't close sockfd, this will prevent further connections from being accepted on the server
-The socket should be closed on both ends in the quit case
-The fact that the client side uses a random port is fine.  Nothing needs to be changed there
© www.soinside.com 2019 - 2024. All rights reserved.