将文件从客户端发送到服务器,然后使用 C 中的套接字在另一个客户端中读取文件

Sending files from a client to a server and then reading the file in another client using sockets in C

应用程序中有两个客户端和一个服务器。两个客户端通过服务器相互通信。当一个客户端向服务器发送消息时,服务器将消息作为文本文件存储在服务器中,文件名为clientid_timestamp.txt。服务器然后将文件发送到读取文件并在其终端上显示其内容的另一个客户端。

我已经为客户端和服务器编写了代码,鉴于 below.The 我面临的问题是客户端无法从服务器打印它 contents.It 的文件t 在终端中显示输出。

Server side image in terminal

client side image in terminal

服务器代码:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <signal.h>

#define MAX_CLIENTS 3
#define BUFFER_SZ 2048
#define SIZE 1024

static _Atomic unsigned int cli_count = 0;
static int uid = 10;

/* Client structure */
typedef struct{
    struct sockaddr_in address;
    int sockfd;
    int uid;
    char name[32];
} client_t;

client_t *clients[MAX_CLIENTS];

pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;

void str_overwrite_stdout() {
    printf("\r%s", "> ");
    fflush(stdout);
}

void print_client_addr(struct sockaddr_in addr){
    printf("%d.%d.%d.%d",
        addr.sin_addr.s_addr & 0xff,
        (addr.sin_addr.s_addr & 0xff00) >> 8,
        (addr.sin_addr.s_addr & 0xff0000) >> 16,
        (addr.sin_addr.s_addr & 0xff000000) >> 24);
}

/* Add clients to queue */
void queue_add(client_t *cl){
    pthread_mutex_lock(&clients_mutex);

    for(int i=0; i < MAX_CLIENTS; ++i){
        if(!clients[i]){
            clients[i] = cl;
            break;
        }
    }

    pthread_mutex_unlock(&clients_mutex);
}

/* Remove clients to queue */
void queue_remove(int uid){
    pthread_mutex_lock(&clients_mutex);

    for(int i=0; i < MAX_CLIENTS; ++i){
        if(clients[i]){
            if(clients[i]->uid == uid){
                clients[i] = NULL;
                break;
            }
        }
    }

    pthread_mutex_unlock(&clients_mutex);
}


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

    FILE *fp = fopen("clientid_timestamp.txt", "r");
    if (fp == NULL){
        printf("Error opening file!\n");
        exit(1);
    
    }

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

}

/* Send message to all clients except sender */
void send_message(char *s, int uid){
    pthread_mutex_lock(&clients_mutex);

    for(int i=0; i<MAX_CLIENTS; ++i){
        if(clients[i]){
            if(clients[i]->uid != uid){
                printf("MESSAGE SENT TO %s:%d \n",inet_ntoa(clients[i]->address.sin_addr),ntohs(clients[i]->address.sin_port));
                send_file(clients[i]->uid);
            }
        }
    }

    pthread_mutex_unlock(&clients_mutex);
}

/* Handle all communication with the client */
void *handle_client(void *arg){

    char buff_out[BUFFER_SZ];
    char name[32];
    int leave_flag = 0;

    cli_count++;
    client_t *cli = (client_t *)arg;

    
    
    // Name

    bzero(buff_out, BUFFER_SZ);

    while(1){
        if (leave_flag) {
            break;
        }

        int receive = recv(cli->sockfd, buff_out, BUFFER_SZ, 0);
        if (receive > 0){
            if(strlen(buff_out) > 0){

                FILE *f = fopen("clientid_timestamp.txt", "w");
                if (f == NULL){
                    printf("Error opening file!\n");
                    exit(1);
                }

                /* print some text */
                fprintf(f, "%s", buff_out);
                send_message(buff_out, cli->uid);
                fclose(f);
                printf("\n");
            } 
        } 
        else {
            printf("ERROR: -1\n");
            leave_flag = 1;
        }

        bzero(buff_out, BUFFER_SZ);
    }

  /* Delete client from queue and yield thread */
    close(cli->sockfd);
    queue_remove(cli->uid);
    free(cli);
    cli_count--;
    pthread_detach(pthread_self());
    return NULL;
}

int main(int argc, char **argv){
    if(argc != 2){
        printf("Usage: %s <port>\n", argv[0]);
        return EXIT_FAILURE;
    }

    char *ip = "127.0.0.1";
    int port = atoi(argv[1]);
    int option = 1;
    int listenfd = 0, connfd = 0;
  struct sockaddr_in serv_addr;
  struct sockaddr_in cli_addr;
  pthread_t tid;

  /* Socket settings */
  listenfd = socket(AF_INET, SOCK_STREAM, 0);
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = inet_addr(ip);
  serv_addr.sin_port = htons(port);

  /* Ignore pipe signals */
    signal(SIGPIPE, SIG_IGN);

    if(setsockopt(listenfd, SOL_SOCKET,(SO_REUSEPORT | SO_REUSEADDR),(char*)&option,sizeof(option)) < 0){
        perror("ERROR: setsockopt failed");
    return EXIT_FAILURE;
    }

    /* Bind */
  if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
    perror("ERROR: Socket binding failed");
    return EXIT_FAILURE;
  }

  /* Listen */
  if (listen(listenfd, 10) < 0) {
    perror("ERROR: Socket listening failed");
    return EXIT_FAILURE;
    }

    printf("=== WELCOME TO THE CHATROOM ===\n");

    char exit[] = "exit_client";
    char accepted[] = "accept_client";

    while(1){
        socklen_t clilen = sizeof(cli_addr);
        connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen);

        /* Check if max clients is reached */
        if((cli_count) == MAX_CLIENTS){
            printf("Max clients reached. Rejected: ");
            print_client_addr(cli_addr);
            printf(":%d\n", cli_addr.sin_port);
            send(connfd, exit, strlen(exit), 0);
            close(connfd);
            continue;
        }
        else{
            
            send(connfd, accepted, strlen(accepted), 0);
            client_t *cli = (client_t *)malloc(sizeof(client_t));
            cli->address = cli_addr;
            cli->sockfd = connfd;
            cli->uid = uid++;

            printf("Client Connected : ");
            printf("%s:%d \n",inet_ntoa(cli->address.sin_addr),ntohs(cli->address.sin_port));
            
            /* Add client to the queue and fork thread */
            queue_add(cli);
            pthread_create(&tid, NULL, &handle_client, (void*)cli);

            /* Reduce CPU usage */
            sleep(1);
        }

        /* Client settings */
        
    }

    return EXIT_SUCCESS;
}

客户代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

#define LENGTH 2048
#define MAX 10000 
// Global variables
volatile sig_atomic_t flag = 0;
int sockfd = 0;
char name[32];

void str_overwrite_stdout() {
  printf("%s", "> ");
  fflush(stdout);
}

void str_trim_lf (char* arr, int length) {
  int i;
  for (i = 0; i < length; i++) { // trim \n
    if (arr[i] == '\n') {
      arr[i] = '[=11=]';
      break;
    }
  }
}

void catch_ctrl_c_and_exit(int sig) {
    flag = 1;
}

void send_msg_handler() {
  char message[LENGTH] = {};
    char buffer[LENGTH + 32] = {};

  while(1) {
    str_overwrite_stdout();
    fgets(message, LENGTH, stdin);
    //str_trim_lf(message, LENGTH);

    if (strcmp(message, "exit") == 0) {
            break;
    } else {
      sprintf(buffer, "%s\n", message);
      send(sockfd, buffer, strlen(buffer), 0);
    }

        bzero(message, LENGTH);
    bzero(buffer, LENGTH + 32);
  }
  catch_ctrl_c_and_exit(2);
}

void recv_msg_handler() {
    

    while (1) {

      int n;
      FILE *fp;
      char buff[1024]="",*ptr=buff;
      int bytes=0,bytes_received;
      while(bytes_received = recv(sockfd,ptr, 1, 0)){

        printf("%s\n",ptr);
        if(bytes_received==-1){
          perror("recieve");
          exit(3);
        }

        if(*ptr=='\n' ) break;
          ptr++; //each times we increment it it points to the buffer element
      }

      *ptr=0;
      ptr=buff;
      printf("%s\n",ptr);
      str_overwrite_stdout();
    }         
}



int main(int argc, char **argv){
    if(argc != 2){
        printf("Usage: %s <port>\n", argv[0]);
        return EXIT_FAILURE;
    }

    char *ip = "127.0.0.1";
    int port = atoi(argv[1]);

    signal(SIGINT, catch_ctrl_c_and_exit);



    struct sockaddr_in server_addr;

    /* Socket settings */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = inet_addr(ip);
  server_addr.sin_port = htons(port);


  // Connect to Server
  int err = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
  if (err == -1) {
        printf("ERROR: connect\n");
        return EXIT_FAILURE;
    }

  char exit_client[] = "exit_client";
  char buff[MAX];
    bzero(buff, sizeof(buff));
  recv(sockfd, buff, 1024, 0);
  if((strcmp(buff, exit_client) == 0)){
    printf("limit exceeded , closing the client \n");
        close(sockfd);
    return EXIT_SUCCESS;
    }

  else{
    printf("client accepted by the server and limit not exceeded \n");
    }
  
    printf("=== WELCOME TO THE CHATROOM ===\n");

    pthread_t send_msg_thread;
  if(pthread_create(&send_msg_thread, NULL, (void *) send_msg_handler, NULL) != 0){
        printf("ERROR: pthread\n");
    return EXIT_FAILURE;
    }

    pthread_t recv_msg_thread;
  if(pthread_create(&recv_msg_thread, NULL, (void *) recv_msg_handler, NULL) != 0){
        printf("ERROR: pthread\n");
        return EXIT_FAILURE;
    }

    while (1){
        if(flag){
            printf("\nBye\n");
            break;
    }
    }

    close(sockfd);

    return EXIT_SUCCESS;
}

EDIT-1

我已经按照用户 stackinside 的建议进行了更改,代码现在可以工作了,但是在过去的几个小时里我遇到了一个新问题,我无法解决这个问题,原因可能是什么为此。

现在出现的问题是客户端只能向其他客户端发送一次消息,反之亦然,然后它不能再发送任何消息,除了基于新的 line.The 更新代码关于我所做的更改

client side image in terminal

server side image in terminal

服务器代码:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <signal.h>

#define MAX_CLIENTS 3
#define BUFFER_SZ 2048
#define SIZE 1024

static _Atomic unsigned int cli_count = 0;
static int uid = 10;

/* Client structure */
typedef struct{
    struct sockaddr_in address;
    int sockfd;
    int uid;
    char name[32];
} client_t;

client_t *clients[MAX_CLIENTS];

void str_trim_lf (char* arr, int length) {
  int i;
  for (i = 0; i < length; i++) { // trim \n
    if (arr[i] == '\n') {
      arr[i] = '[=12=]';
      break;
    }
  }
}

pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;

void str_overwrite_stdout() {
    printf("\r%s", "> ");
    fflush(stdout);
}

void print_client_addr(struct sockaddr_in addr){
    printf("%d.%d.%d.%d",
        addr.sin_addr.s_addr & 0xff,
        (addr.sin_addr.s_addr & 0xff00) >> 8,
        (addr.sin_addr.s_addr & 0xff0000) >> 16,
        (addr.sin_addr.s_addr & 0xff000000) >> 24);
}

/* Add clients to queue */
void queue_add(client_t *cl){
    pthread_mutex_lock(&clients_mutex);

    for(int i=0; i < MAX_CLIENTS; ++i){
        if(!clients[i]){
            clients[i] = cl;
            break;
        }
    }

    pthread_mutex_unlock(&clients_mutex);
}

/* Remove clients to queue */
void queue_remove(int uid){
    pthread_mutex_lock(&clients_mutex);

    for(int i=0; i < MAX_CLIENTS; ++i){
        if(clients[i]){
            if(clients[i]->uid == uid){
                clients[i] = NULL;
                break;
            }
        }
    }

    pthread_mutex_unlock(&clients_mutex);
}


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

    FILE *fp = fopen("clientid_timestamp.txt", "r");
    if (fp == NULL){
        printf("Error opening file!\n");
        exit(1);
    
    }

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

/* Send message to all clients except sender */
void send_message(char *s, int uid){
    pthread_mutex_lock(&clients_mutex);

    for(int i=0; i<MAX_CLIENTS; ++i){
        if(clients[i]){
            if(clients[i]->uid != uid){
                printf("MESSAGE SENT TO %s:%d \n",inet_ntoa(clients[i]->address.sin_addr),ntohs(clients[i]->address.sin_port));
                send_file(clients[i]->sockfd);
            }
        }
    }

    pthread_mutex_unlock(&clients_mutex);
}

/* Handle all communication with the client */
void *handle_client(void *arg){

    char buff_out[BUFFER_SZ];
    char name[32];
    int leave_flag = 0;

    cli_count++;
    client_t *cli = (client_t *)arg;

    
    
    // Name

    bzero(buff_out, BUFFER_SZ);

    while(1){
        if (leave_flag) {
            break;
        }

        int receive = recv(cli->sockfd, buff_out, BUFFER_SZ, 0);
        if (receive > 0){
            if(strlen(buff_out) > 0){

                FILE *f = fopen("clientid_timestamp.txt", "w");
                if (f == NULL){
                    printf("Error opening file!\n");
                    exit(1);
                }

                /* print some text */
                fprintf(f, "%s", buff_out);
                fclose(f);
                send_message(buff_out, cli->uid);
                printf("\n");
            } 
        } 
        else {
            printf("ERROR: -1\n");
            leave_flag = 1;
        }

        bzero(buff_out, BUFFER_SZ);
    }

  /* Delete client from queue and yield thread */
    close(cli->sockfd);
    queue_remove(cli->uid);
    free(cli);
    cli_count--;
    pthread_detach(pthread_self());
    return NULL;
}

int main(int argc, char **argv){
    if(argc != 2){
        printf("Usage: %s <port>\n", argv[0]);
        return EXIT_FAILURE;
    }

    char *ip = "127.0.0.1";
    int port = atoi(argv[1]);
    int option = 1;
    int listenfd = 0, connfd = 0;
  struct sockaddr_in serv_addr;
  struct sockaddr_in cli_addr;
  pthread_t tid;

  /* Socket settings */
  listenfd = socket(AF_INET, SOCK_STREAM, 0);
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = inet_addr(ip);
  serv_addr.sin_port = htons(port);

  /* Ignore pipe signals */
    signal(SIGPIPE, SIG_IGN);

    if(setsockopt(listenfd, SOL_SOCKET,(SO_REUSEPORT | SO_REUSEADDR),(char*)&option,sizeof(option)) < 0){
        perror("ERROR: setsockopt failed");
    return EXIT_FAILURE;
    }

    /* Bind */
  if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
    perror("ERROR: Socket binding failed");
    return EXIT_FAILURE;
  }

  /* Listen */
  if (listen(listenfd, 10) < 0) {
    perror("ERROR: Socket listening failed");
    return EXIT_FAILURE;
    }

    printf("=== WELCOME TO THE CHATROOM ===\n");

    char exit[] = "exit_client";
    char accepted[] = "accept_client";

    while(1){
        socklen_t clilen = sizeof(cli_addr);
        connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen);

        /* Check if max clients is reached */
        if((cli_count) == MAX_CLIENTS){
            printf("Max clients reached. Rejected: ");
            print_client_addr(cli_addr);
            printf(":%d\n", cli_addr.sin_port);
            send(connfd, exit, strlen(exit), 0);
            close(connfd);
            continue;
        }
        else{
            
            send(connfd, accepted, strlen(accepted), 0);
            client_t *cli = (client_t *)malloc(sizeof(client_t));
            cli->address = cli_addr;
            cli->sockfd = connfd;
            cli->uid = uid++;

            printf("Client Connected : ");
            printf("%s:%d \n",inet_ntoa(cli->address.sin_addr),ntohs(cli->address.sin_port));
            
            /* Add client to the queue and fork thread */
            queue_add(cli);
            pthread_create(&tid, NULL, &handle_client, (void*)cli);

            /* Reduce CPU usage */
            sleep(1);
        }

        /* Client settings */
        
    }

    return EXIT_SUCCESS;
}

客户代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

#define LENGTH 2048
#define MAX 10000 
// Global variables
volatile sig_atomic_t flag = 0;
int sockfd = 0;
char name[32];

void str_overwrite_stdout() {
  printf("%s", "> ");
  fflush(stdout);
}

void str_trim_lf (char* arr, int length) {
  int i;
  for (i = 0; i < length; i++) { // trim \n
    if (arr[i] == '\n') {
      arr[i] = '[=13=]';
      break;
    }
  }
}

void catch_ctrl_c_and_exit(int sig) {
    flag = 1;
}

void send_msg_handler() {
  char message[LENGTH] = {};
    char buffer[LENGTH + 32] = {};

  while(1) {
    str_overwrite_stdout();
    fgets(message, LENGTH, stdin);
    str_trim_lf(message, LENGTH);

    if (strcmp(message, "exit") == 0) {
            break;
    } else {
      sprintf(buffer, "%s\n", message);
      send(sockfd, buffer, strlen(buffer), 0);
    }

        bzero(message, LENGTH);
    bzero(buffer, LENGTH + 32);
  }
  catch_ctrl_c_and_exit(2);
}

void recv_msg_handler() {

    int n;
    FILE *fp;
    char buff[1024]="",*ptr=buff;
    int bytes=0,bytes_received;
  
    while (1) {

      
      while(bytes_received = recv(sockfd,ptr, 1, 0)){

        if(bytes_received==-1){
          perror("recieve");
          exit(3);
        }

        if(*ptr=='\n' ) break;
          ptr++; //each times we increment it it points to the buffer element
      }
      *ptr=0;
      str_trim_lf(buff, strlen(buff));
      ptr=buff;
      printf("%s \n",ptr);
      str_overwrite_stdout();
    }         
}



int main(int argc, char **argv){
    if(argc != 2){
        printf("Usage: %s <port>\n", argv[0]);
        return EXIT_FAILURE;
    }

    char *ip = "127.0.0.1";
    int port = atoi(argv[1]);

    signal(SIGINT, catch_ctrl_c_and_exit);



    struct sockaddr_in server_addr;

    /* Socket settings */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = inet_addr(ip);
  server_addr.sin_port = htons(port);


  // Connect to Server
  int err = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
  if (err == -1) {
        printf("ERROR: connect\n");
        return EXIT_FAILURE;
    }

  char exit_client[] = "exit_client";
  char buff[MAX];
    bzero(buff, sizeof(buff));
  recv(sockfd, buff, 1024, 0);
  if((strcmp(buff, exit_client) == 0)){
    printf("limit exceeded , closing the client \n");
        close(sockfd);
    return EXIT_SUCCESS;
    }

  else{
    printf("client accepted by the server and limit not exceeded \n");
    }
  
    printf("=== WELCOME TO THE CHATROOM ===\n");

    pthread_t send_msg_thread;
  if(pthread_create(&send_msg_thread, NULL, (void *) send_msg_handler, NULL) != 0){
        printf("ERROR: pthread\n");
    return EXIT_FAILURE;
    }

    pthread_t recv_msg_thread;
  if(pthread_create(&recv_msg_thread, NULL, (void *) recv_msg_handler, NULL) != 0){
        printf("ERROR: pthread\n");
        return EXIT_FAILURE;
    }

    while (1){
        if(flag){
            printf("\nBye\n");
            break;
    }
    }

    close(sockfd);

    return EXIT_SUCCESS;
}

EDIT-2

所以现在我按照 user207421、Martin James 和 stackinside 的建议将 fgets 更改为 freads 并删除了所有不必要的 bzero 并将 strlen 更改为 sizeof。它终于起作用了,我同意还有很多有优化的余地,但目前有效,感谢您的努力。

client side image in terminal

Server side image in terminal

客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

#define LENGTH 2048
#define MAX 10000 
#define CHUNK_SIZE 512
// Global variables
volatile sig_atomic_t flag = 0;
int sockfd = 0;
char name[32];

void str_overwrite_stdout() {
  printf("%s", "> ");
  fflush(stdout);
}

void str_trim_lf (char* arr, int length) {
  int i;
  for (i = 0; i < length; i++) { // trim \n
    if (arr[i] == '\n') {
      arr[i] = '[=14=]';
      break;
    }
  }
}

void catch_ctrl_c_and_exit(int sig) {
    flag = 1;
}

void send_msg_handler() {
  char message[LENGTH] = {};
    char buffer[LENGTH + 32] = {};

  while(1) {
    str_overwrite_stdout();
    
    fgets(message, LENGTH, stdin);
    str_trim_lf(message, LENGTH);

    if (strcmp(message, "exit") == 0) {
            break;
    } 
    
    else {
      sprintf(buffer, "%s\n", message);
      send(sockfd, buffer, sizeof(buffer), 0);
    }

        bzero(message, LENGTH);
    bzero(buffer, LENGTH + 32);
  }

  catch_ctrl_c_and_exit(2);
}

void recv_msg_handler() {

    while (1) {

        int n;
        FILE *fp;
        char buff[1024],*ptr=buff;
        int bytes=0,bytes_received;
        int file_size;

        recv(sockfd, buff, CHUNK_SIZE, 0);
        file_size = atoi(buff);
        
        str_trim_lf(buff, sizeof(buff));

        printf("%s \n",buff);
        str_overwrite_stdout();
    }         
}



int main(int argc, char **argv){
    if(argc != 2){
        printf("Usage: %s <port>\n", argv[0]);
        return EXIT_FAILURE;
    }

    char *ip = "127.0.0.1";
    int port = atoi(argv[1]);

    signal(SIGINT, catch_ctrl_c_and_exit);



    struct sockaddr_in server_addr;

    /* Socket settings */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = inet_addr(ip);
  server_addr.sin_port = htons(port);


  // Connect to Server
  int err = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
  if (err == -1) {
        printf("ERROR: connect\n");
        return EXIT_FAILURE;
    }

  char exit_client[] = "exit_client";
  char buff[MAX];
    bzero(buff, sizeof(buff));
  recv(sockfd, buff, 1024, 0);

  if((strcmp(buff, exit_client) == 0)){
    printf("limit exceeded , closing the client \n");
        close(sockfd);
    return EXIT_SUCCESS;
    }

  else{
    printf("client accepted by the server and limit not exceeded \n");
    }
  
    printf("=== WELCOME TO THE CHATROOM ===\n");

    pthread_t send_msg_thread;
  if(pthread_create(&send_msg_thread, NULL, (void *) send_msg_handler, NULL) != 0){
        printf("ERROR: pthread\n");
    return EXIT_FAILURE;
    }

    pthread_t recv_msg_thread;
  if(pthread_create(&recv_msg_thread, NULL, (void *) recv_msg_handler, NULL) != 0){
        printf("ERROR: pthread\n");
        return EXIT_FAILURE;
    }

    while (1){
        if(flag){
            printf("\nBye\n");
            break;
    }
    }

    close(sockfd);

    return EXIT_SUCCESS;
}

服务器端:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <signal.h>

#define MAX_CLIENTS 3
#define BUFFER_SZ 2048
#define SIZE 1024
#define CHUNK_SIZE 512

static _Atomic unsigned int cli_count = 0;
static int uid = 10;

/* Client structure */
typedef struct{
    struct sockaddr_in address;
    int sockfd;
    int uid;
    char name[32];
} client_t;

client_t *clients[MAX_CLIENTS];

void str_trim_lf (char* arr, int length) {
  int i;
  for (i = 0; i < length; i++) { // trim \n
    if (arr[i] == '\n') {
      arr[i] = '[=15=]';
      break;
    }
  }
}

pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;

void str_overwrite_stdout() {
    printf("\r%s", "> ");
    fflush(stdout);
}

void print_client_addr(struct sockaddr_in addr){
    printf("%d.%d.%d.%d",
        addr.sin_addr.s_addr & 0xff,
        (addr.sin_addr.s_addr & 0xff00) >> 8,
        (addr.sin_addr.s_addr & 0xff0000) >> 16,
        (addr.sin_addr.s_addr & 0xff000000) >> 24);
}

/* Add clients to queue */
void queue_add(client_t *cl){
    pthread_mutex_lock(&clients_mutex);

    for(int i=0; i < MAX_CLIENTS; ++i){
        if(!clients[i]){
            clients[i] = cl;
            break;
        }
    }

    pthread_mutex_unlock(&clients_mutex);
}

/* Remove clients to queue */
void queue_remove(int uid){
    pthread_mutex_lock(&clients_mutex);

    for(int i=0; i < MAX_CLIENTS; ++i){
        if(clients[i]){
            if(clients[i]->uid == uid){
                clients[i] = NULL;
                break;
            }
        }
    }

    pthread_mutex_unlock(&clients_mutex);
}


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

    FILE *fp = fopen("clientid_timestamp.txt", "r");
    if (fp == NULL){
        printf("Error opening file!\n");
        exit(1);
    
    }

    char file_data[CHUNK_SIZE];
    size_t nbytes = 0;

    while ( (nbytes = fread(data, sizeof(char), CHUNK_SIZE,fp)) > 0){
        
        if (send(sockfd, data, nbytes, 0) == -1) {
        perror("[-]Error in sending file.");
        exit(1);
    }
    }
}

/* Send message to all clients except sender */
void send_message(char *s, int uid){
    pthread_mutex_lock(&clients_mutex);

    for(int i=0; i<MAX_CLIENTS; ++i){
        if(clients[i]){
            if(clients[i]->uid != uid){
                printf("MESSAGE SENT TO %s:%d \n",inet_ntoa(clients[i]->address.sin_addr),ntohs(clients[i]->address.sin_port));
                send_file(clients[i]->sockfd);
            }
        }
    }

    pthread_mutex_unlock(&clients_mutex);
}

/* Handle all communication with the client */
void *handle_client(void *arg){

    char buff_out[BUFFER_SZ];
    char name[32];
    int leave_flag = 0;

    cli_count++;
    client_t *cli = (client_t *)arg;

    // Name

    bzero(buff_out, BUFFER_SZ);

    while(1){
        if (leave_flag) {
            break;
        }

        int receive = recv(cli->sockfd, buff_out, BUFFER_SZ, 0);
        if (receive > 0){
            if(strlen(buff_out) > 0){

                FILE *f = fopen("clientid_timestamp.txt", "w");
                if (f == NULL){
                    printf("Error opening file!\n");
                    exit(1);
                }

                /* print some text */
                fprintf(f, "%s", buff_out);
                fclose(f);
                send_message(buff_out, cli->uid);
                printf("\n");
            } 
        } 

        else {
            printf("ERROR: -1\n");
            leave_flag = 1;
        }

    }

  /* Delete client from queue and yield thread */
    close(cli->sockfd);
    queue_remove(cli->uid);
    free(cli);
    cli_count--;
    pthread_detach(pthread_self());
    return NULL;
}

int main(int argc, char **argv){

    if(argc != 2){
        printf("Usage: %s <port>\n", argv[0]);
        return EXIT_FAILURE;
    }

    char *ip = "127.0.0.1";
    int port = atoi(argv[1]);
    int option = 1;
    int listenfd = 0, connfd = 0;
    struct sockaddr_in serv_addr;
    struct sockaddr_in cli_addr;
    pthread_t tid;

  /* Socket settings */
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(ip);
    serv_addr.sin_port = htons(port);

  /* Ignore pipe signals */
    signal(SIGPIPE, SIG_IGN);

    if(setsockopt(listenfd, SOL_SOCKET,(SO_REUSEPORT | SO_REUSEADDR),(char*)&option,sizeof(option)) < 0){
        perror("ERROR: setsockopt failed");
    return EXIT_FAILURE;
    }

    /* Bind */
    if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("ERROR: Socket binding failed");
        return EXIT_FAILURE;
    }

  /* Listen */
    if (listen(listenfd, 10) < 0) {
        perror("ERROR: Socket listening failed");
        return EXIT_FAILURE;
        }

    printf("=== WELCOME TO THE CHATROOM ===\n");

    char exit[] = "exit_client";
    char accepted[] = "accept_client";

    while(1){
        socklen_t clilen = sizeof(cli_addr);
        connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen);

        /* Check if max clients is reached */
        if((cli_count) == MAX_CLIENTS){
            printf("Max clients reached. Rejected: ");
            print_client_addr(cli_addr);
            printf(":%d\n", cli_addr.sin_port);
            send(connfd, exit, sizeof(exit), 0);
            close(connfd);
            continue;
        }
        else{
            
            send(connfd, accepted, sizeof(accepted), 0);
            client_t *cli = (client_t *)malloc(sizeof(client_t));
            cli->address = cli_addr;
            cli->sockfd = connfd;
            cli->uid = uid++;

            printf("Client Connected : ");
            printf("%s:%d \n",inet_ntoa(cli->address.sin_addr),ntohs(cli->address.sin_port));
            
            /* Add client to the queue and fork thread */
            queue_add(cli);
            pthread_create(&tid, NULL, &handle_client, (void*)cli);

            /* Reduce CPU usage */
            sleep(1);
        }

        /* Client settings */
        
    }

    return EXIT_SUCCESS;
}

服务器端:

  • send_file(clients[i]->uid); 应该是 send_file(clients[i]->sockfd);
  • fclose(f); 应该在 之前 send_message(buff_out, cli->uid);

客户端:

  • printf("%s\n",ptr);(在 if(bytes_received==-1) 之前)应该被删除

还有其他不一致,未使用的变量等,这次reivew非常有限。