开天辟地的卷毛 2023-06-06 13:08 采纳率: 83.7%
浏览 9
已结题

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

#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;
}

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

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

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

  • 写回答

1条回答 默认 最新

  • Leodong. 2023-06-06 13:52
    关注

    该回答通过自己思路及引用到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,可以根据实际需求进行调整。


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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 9月20日
  • 已采纳回答 9月12日
  • 创建了问题 6月6日

悬赏问题

  • ¥15 Android studio AVD启动不了
  • ¥15 陆空双模式无人机怎么做
  • ¥15 想咨询点问题,与算法转换,负荷预测,数字孪生有关
  • ¥15 C#中的编译平台的区别影响
  • ¥15 软件供应链安全是跟可靠性有关还是跟安全性有关?
  • ¥15 电脑蓝屏logfilessrtsrttrail问题
  • ¥20 关于wordpress建站遇到的问题!(语言-php)(相关搜索:云服务器)
  • ¥15 【求职】怎么找到一个周围人素质都很高不会欺负他人,并且未来月薪能够达到一万以上(技术岗)的工作?希望可以收到写有具体,可靠,已经实践过了的路径的回答?
  • ¥15 Java+vue部署版本反编译
  • ¥100 对反编译和ai熟悉的开发者。