首页 > 其他分享 >利用线程池和网络动态库实现多人聊天室

利用线程池和网络动态库实现多人聊天室

时间:2024-10-12 13:46:22浏览次数:9  
标签:index 聊天室 int clients 线程 多人 include buf nw

利用线程池和网络动态库实现多人聊天室

在这里插入图片描述

概述

本项目实现一个简单的多人聊天室,采用C语言编写,利用线程池和网络动态库,实现服务端消息转发和客户端消息接收。

服务端

服务端主要负责管理客户端连接,接收并转发消息。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <network.h> // 自己封装的网络动态库
#include <pthread.h>
#include "threadpool.h" // 自己封装的线程池工具

#define BUFFER_SIZE 1024
#define MAX_CLIENT 50

// 在线客户端数组
Network *clients[MAX_CLIENT];

// 添加到客户端
int add_clients(Network *nw) {
    for (int i = 0; i < MAX_CLIENT; i++) {
        if (NULL == clients[i]) {
            clients[i] = nw;
            return i;
        }
    }
    return -1; // 返回错误状态
}

// 转发消息给其他客户端
void send_clients(int index, char *str) {
    for (int i = 0; i < MAX_CLIENT; i++) {
        if (NULL != clients[i] && i != index) {
            send_nw(clients[i], str, strlen(str) + 1);
        }
    }
}

// 处理客户端进入聊天室的逻辑
void enter(void *arg) {
    int index = add_clients(arg);
    char *buf = malloc(BUFFER_SIZE);

    // 接收昵称
    int ret = recv_nw(clients[index], buf, BUFFER_SIZE);
    if (ret <= 0 || 0 == strcmp(buf, "quit")) {
        close_nw(clients[index]);
        clients[index] = NULL;
        free(buf);
        return;
    }
    strcat(buf, "进入了聊天室,大家小心!\n");
    send_clients(index, buf);

    // 设置昵称后添加冒号
    buf[ret - 1] = ':';
    char *msg = buf + ret;

    // 接收消息
    for (;;) {
        int ret = recv_nw(clients[index], msg, BUFFER_SIZE);
        if (ret <= 0 || 0 == strcmp(msg, "quit\n")) {
            sprintf(msg, "离开了聊天室!\n");
            send_clients(index, buf);
            close_nw(clients[index]);
            clients[index] = NULL;
            free(buf);
            return;
        }
        send_clients(index, buf);
    }
}

int main(int argc, char *argv[]) {
    // 检查命令行参数
    if (3 != argc) {
        printf("Usage: chat_ser <ip> <port>\n");
        return EXIT_FAILURE;
    }

    // 创建线程池
    ThreadPool *threadpool = creat_threadpool(50, 20, enter);
    start_threadpool(threadpool);

    // 启动网络通信
    Network *svr_nw = init_nw(SOCK_STREAM, atoi(argv[2]), argv[1], true);
    if (NULL == svr_nw) {
        printf("Server network init failed!\n");
        return EXIT_FAILURE;
    }

    for (;;) {
        // 等待客户端连接
        Network *clt_nw = accept_nw(svr_nw);
        if (NULL == clt_nw) {
            printf("Accept client failed!\n");
            continue;
        }
        // 添加到线程池
        push_threadpool(threadpool, clt_nw);
    }
}

客户端

客户端负责连接到服务器,并发送和接收消息。

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <network.h>
#include <pthread.h>

char buf[1024] = {};
size_t buf_size = sizeof(buf);

void* run(void* arg) {
    Network* nw = (Network*)arg;
    for (;;) {
        int ret = recv_nw(nw, buf, buf_size);
        if (ret <= 0) {
            puts("服务器正在升级,请检查\n");
            exit(EXIT_FAILURE);
        }
        printf("\r----%s\n", buf);
        printf(">>>>>>>>>>");
        fflush(stdout);
    }
}

int main(int argc, const char* argv[]) {
    if (argc != 3) {
        printf("Usage: %s <server_ip> <server_port>\n", argv[0]);
        return 1;
    }
    
    Network* nw = init_nw(SOCK_STREAM, atoi(argv[2]), argv[1], false);
    if (nw == NULL) {
        printf("网络错误,请检查\n");
        return EXIT_FAILURE;
    }

    printf("请输入你的昵称:");
    scanf("%s", buf);
    send_nw(nw, buf, strlen(buf) + 1);

    pthread_t tid;
    pthread_create(&tid, NULL, run, nw);

    for (;;) {
        printf(">>>>>>>>>");
        fgets(buf, sizeof(buf), stdin);
        int ret = send_nw(nw, buf, strlen(buf) + 1);
        if (0 == strcmp(buf, "quit\n")) {
            puts("退出聊天室\n");
            return EXIT_SUCCESS;
        }
        if (ret <= 0) {
            puts("服务器正在升级,请检查\n");
            return EXIT_FAILURE;
        }
    }

    return 0;
}

总结

此聊天室实现了基本的多人聊天功能,使用服务器转发消息给其他客户端,结合线程池提高并发处理能力。你可以在此基础上扩展更多功能,比如昵称验证、聊天记录保存等。

标签:index,聊天室,int,clients,线程,多人,include,buf,nw
From: https://blog.csdn.net/m0_57538342/article/details/142874830

相关文章

  • Redis 单线程模型
    Redis是单线程的,但仍然非常快,主要得益于以下几个因素:I/O多路复用:Redis使用I/O多路复用技术(比如epoll),使它能够高效处理大量连接,即便是单线程内存操作:Redis的大部分操作都是内存级别的,避免了磁盘I/O的瓶颈避免上下文切换:由于是单线程,Redis不需要频繁地在线程之间切换,......
  • linux中的线程
    线程一个进程可以包含多个线程。同一程序中的所有线程均会独立执行相同程序,且共享同一份全局内存区域,其中包括初始化数据段(initializeddata)、未初始化数据段(uninitializeddata),以及堆内存段(heapsegment)多线程的进程内存布局文本段、数据段这些,线程共享,然后会为每个线程分......
  • gdb多线程多进程调试命令
    多线程infothreads查看当前所有运行线程的列表thread线程编号 切换到特定线程进行调试setscheduler-lockingon只运行当前线程,停止其他线程进行调试多进程infoinferions显示所有正在调试的进程inferion进程编号 切换到特定进程运行,同时挂起其他进程detach-on-fo......
  • Java并发编程-线程池
    ThreadLocal应用场景:两个线程争执一个资源。解决问题:实现每个线程绑定自己的专属本地变量,可以将ThreadLocal类理解成存放数据的盒子,盒子中存放每个线程的私有数据。线程池的用途选择快速响应用户请求:比如说用户查询商品详情页,会涉及查询商品关联的一系列信息如价格、优......
  • Vector线程安全问题
    背景在韩顺平的Java课程中,有一个坦克大战练习项目,其中有这样一个功能需求:敌人坦克自动发射多个子弹,检测子弹是否击中我方坦克。视频中使用的是Vector存储这个子弹队列。代码实现对于这一部分,我的实现代码是://MyPanel.java的run()方法while(true){try{Thr......
  • 聊天室(Websocket+Node)
    文章目录目录文章目录前言二、使用步骤1.服务端代码 2.客户端代码3.成果展示总结前言使用Websocket+Node实现一个简单的聊天室的功能,以及包含保持websocket长时间连接永不断开的两种方法一、Websocket是什么?WebSocket是一种网络通信协议,是 HTML5 开始提供......
  • C# 线程---Thread1
     1.thread不带参数(Main和Thread都在同步处理)(注意usingstatic和System.Console的使用)usingstaticSystem.Console;namespaceRecipe1{classProgram{staticvoidMain(string[]args){Threadt=newThread(PrintNumber);......
  • Windows多线程编程 互斥量和临界区使用
    Windows多线程编程允许程序同时运行多个线程,提高程序的并发性和执行效率。多线程编程中的核心概念包括线程的创建、同步、调度、数据共享和竞争条件等。本文详细介绍了Windows多线程编程的关键技术点,并解释如何使用线程同步机制来保证线程安全。1.线程基础概念1.1线......
  • DAY 4 线程安全的问题
    比如有一个三个窗口卖票系统 就会遇到三个线程互不影响去卖300张票,这时候就需要在定义的m加上static关键字,意思就是共享m的数据解决方法同步代码块同步代码块就是把操作共享数据的代码锁起来  (1)锁默认打开,有一个线程进去了,锁自动关闭(2)里面的代码全部执行完毕......
  • JDK线程池详解(全网最全-原理解析、源码详解)
    频繁创建新线程的缺点?不受控风险系统资源有限,每个人针对不同业务都可以手动创建线程,并且创建标准不一样(比如线程没有名字)。当系统运行起来,所有线程都在疯狂抢占资源,毫无规则,不好管控。另外,过多的线程自然也会引起上下文切换的开销。频繁创建开销大newThread()在操作系统层......