关于多线程网络编程的问题

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

void *send_message(void *arg)
{
    int fd = *(int *)arg;
    char buf[1024] = {0};
    while (1)
    {
        bzero(buf, 1024);
        fgets(buf, 1024, stdin);
        write(fd, buf, 1024);
    }
}

void *recv_msg(void *arg)
{
    int com_fd = *(int *)arg;
    char buf[1024] = {0};
    while (1)
    {
        bzero(buf, 1024);
        read(com_fd, buf, 1024);
        printf("from client:%s\n", buf);
    }
    return NULL;
}

int main(int argc, char const *argv[])
{
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serveraddr;
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(50001);
    serveraddr.sin_addr.s_addr = htonl(INADR_ANY);
    bind(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    listen(fd, 4);
    struct sockaddr_in clientaddr;
    socklen_t len = sizeof(clientaddr);
    pthread_t tid[10];
    int i = 0;
    while (1)
    {
        int com_fd = accept(fd, (struct sockaddr *)&clientaddr, &len);

        printf("new connetion:%s : %hu\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
        pthread_create(&tid[i], NULL, recv_msg, &com_fd);
        pthread_create(&tid[i+1], NULL, send_message, &com_fd);
        i += 2;
    }
    close(fd);
    return 0;
}

想要实现的是:编程实现服务器能够接受多个客户端的连接请求,并且能够与多个客户端互相收发数据

但是目前的问题是只能多个客户端发送信息给服务端,服务端不能发信息给各个客户端。

有什么办法可以解决这个问题吗

该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
在当前代码中,主线程只负责循环接受客户端连接请求,并创建两个线程分别用于接收客户端消息和发送消息给客户端。但是,发送消息的线程只负责从标准输入中读取消息,并发送给最后一个连接的客户端,而没有对多个连接的客户端进行处理。

为了实现服务端向多个客户端发送消息的功能,可以在主线程中维护一个客户端列表,每当有新的连接请求时,就将新的客户端连接添加到列表中。然后,当发送消息时,就遍历客户端列表,向每个客户端发送消息。

以下是修改后的代码:

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

#define MAX_CLIENTS 10

int clients[MAX_CLIENTS]; // 客户端连接列表
int nclients = 0; // 当前客户端连接数

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁,用于保护客户端连接列表

void *send_message(void *arg)
{
    int fd = *(int *)arg;
    char buf[1024] = {0};
    while (1)
    {
        bzero(buf, 1024);
        fgets(buf, 1024, stdin);

        // 向客户端发送消息
        pthread_mutex_lock(&mutex);
        for (int i = 0; i < nclients; i++) {
            write(clients[i], buf, 1024);
        }
        pthread_mutex_unlock(&mutex);
    }
}

void *recv_msg(void *arg)
{
    int com_fd = *(int *)arg;
    char buf[1024] = {0};
    while (1)
    {
        bzero(buf, 1024);
        read(com_fd, buf, 1024);
        printf("from client:%s\n", buf);

        // 向客户端发送消息
        pthread_mutex_lock(&mutex);
        for (int i = 0; i < nclients; i++) {
            write(clients[i], buf, 1024);
        }
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main(int argc, char const *argv[])
{
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in serveraddr;
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(50001);
    serveraddr.sin_addr.s_addr = htonl(INADR_ANY);
    bind(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
    listen(fd, 4);
    struct sockaddr_in clientaddr;
    socklen_t len = sizeof(clientaddr);
    pthread_t tid[10];
    int i = 0;
    while (1)
    {
        int com_fd = accept(fd, (struct sockaddr *)&clientaddr, &len);

        printf("new connetion:%s : %hu\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

        // 添加新的客户端连接到列表中
        pthread_mutex_lock(&mutex);
        if (nclients < MAX_CLIENTS) {
            clients[nclients] = com_fd;
            nclients++;
        } else {
            close(com_fd);
        }
        pthread_mutex_unlock(&mutex);

        // 创建线程用于接收客户端消息
        pthread_create(&tid[i], NULL, recv_msg, &com_fd);

        // 创建线程用于发送消息给客户端
        pthread_create(&tid[i+1], NULL, send_message, NULL);

        i += 2;
    }
    close(fd);
    return 0;
}

在修改后的代码中,添加了一个数组 clients 用于存储客户端连接句柄。在主线程中,每当有新的客户端连接请求时,就将新的客户端连接句柄添加到 clients 中,然后增加 nclients 的值。为了保证线程安全,添加了互斥锁 mutex,在修改 clientsnclients 的时候需要先获取这个锁。

在发送消息时,遍历 clients 数组,向每个客户端发送消息。因为多个线程可能同时访问 clients数组,所以在遍历 clients 数组时也需要先获取互斥锁 mutex

需要注意的是,为了避免客户端连接列表被填满,需要限制客户端连接数的最大值,并在达到最大值时拒绝新的连接请求。在上面的代码中,将最大连接数设置为 10,可以根据实际需求进行调整。


如果以上回答对您有所帮助,点击一下采纳该答案~谢谢