当前位置: 首页 > article >正文

网络编程--服务器双客户端聊天

写一个服务器和客户端

运行服务器和2个客户端,实现聊天功能 客户端1和客户端2进行聊天,客户端1将聊天数据发送给服务器,服务器将聊天数据转发给客户端2

要求: 服务器使用 select 模型实现 ,客户端1使用 poll 模型实现, 客户端2使用多线程实现

服务器:

#include <head.h>
// 将client存入数组arr中的最后一个位置上,存完之后,arr数组的长度记得自增
void insert_client(int arr[], int client, int *len) {
    arr[*len] = client;
    (*len)++;
}

// 将client从数组arr中移除,移除后记得数组长度-1
void remove_client(int arr[], int client, int *len) {
    int i;
    for (i = 0; i < *len; i++) {
        if (arr[i] == client) {
            break;
        }
    }
    if (i == *len) {
        return;
    }
    for (; i < (*len - 1); i++) {
        arr[i] = arr[i + 1];
    }
    (*len)--;
}

int main(int argc, const char *argv[]) {
    if (argc < 2) {
        printf("请输入端口号\n");
        return 1;
    }
    int port = atoi(argv[1]);

    // 创建服务器套接字
    int server = socket(AF_INET, SOCK_STREAM, 0);

    // 为服务器准备ip和port
    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr("0.0.0.0");

    if (bind(server, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("bind");
        return 1;
    }
    listen(server, 50);

    int client_arr[64] = {0}; // 用来存放所有客户端套接字的数组
    int arr_len = 0;         // 记录数组的长度
    fd_set readfds;         // 创建一个select的监视列表

    // 初始化,只有2个描述符可以初始化,1个是server服务器套接字,1个是标准输入流 0
    FD_ZERO(&readfds);
    FD_SET(server, &readfds);    // 将服务器套接字放入到监视列表中
    FD_SET(STDIN_FILENO, &readfds); // 将标准输入流描述符放入到监视列表中

    while (1) {
        fd_set temp = readfds;
        select(1024, &temp, 0, 0, 0);
        // select是一个阻塞型函数,一旦接触阻塞,就说明有任意个描述符激活了,激活的描述符会写入temp里面
        // 判断一下激活列表temp里面的描述符到底是哪些
        if (FD_ISSET(STDIN_FILENO, &temp)) {
            char buf[1024] = {0};
            scanf("%s", buf);
            printf("键盘输入数据:%s\n", buf);
        }
        if (FD_ISSET(server, &temp)) {
            int client = accept(server, 0, 0);
            printf("有新客户端连接\n");

            // 将新连接的客户端加入到监视列表 readfds里面去 以及 数组 client_arr里面去
            FD_SET(client, &readfds);
            insert_client(client_arr, client, &arr_len);
        }

        // 判断一下各种各样的客户端是否被激活,也就是是否有在temp 里面
        for (int i = 0; i < arr_len; i++) {
            int client = client_arr[i];
            if (FD_ISSET(client, &temp)) {
                char pack[1024] = {0};
                int size = 0;
                int res = read(client, &size, 4);
                if (res == 0) {
                    printf("从客户端断开连接\n");
                    // 从监视列表和客户端数组中移除客户端套接字
                    FD_CLR(client, &readfds);
                    remove_client(client_arr, client, &arr_len);
                    close(client); // 关闭相关的客户端
                    break;
                }
                read(client, (char *)&pack + 4, size - 4);
                // 转发数据给其他客户端
                for (int j = 0; j < arr_len; j++) {
                    if (client_arr[j] != client) {
                        write(client_arr[j], &size, 4);
                        write(client_arr[j], pack, size);
                    }
                }
            }
        }
    }
    return 0;
}

客户端1:

#include <head.h>
// 将client存入数组arr中的最后一个位置上,存完之后,arr数组的长度记得自增
void insert_client(struct pollfd *arr, struct pollfd client, int *len) {
    arr[*len] = client;
    (*len)++;
}

// 将client从数组arr中移除,移除后记得数组长度-1
void remove_client(struct pollfd *arr, int client, int *len) {
    int i;
    for (i = 0; i < *len; i++) {
        if (arr[i].fd == client) {
            break;
        }
    }
    if (i == *len) {
        return;
    }
    for (; i < (*len - 1); i++) {
        arr[i] = arr[i + 1];
    }
    (*len)--;
}

int main(int argc, const char *argv[]) {
    if (argc < 2) {
        printf("请输入端口号\n");
        return 1;
    }
    int port = atoi(argv[2]);

    // 创建客户端套接字
    int client = socket(AF_INET, SOCK_STREAM, 0);

    // 准备 ip 和 port
    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr("192.168.126.235");

    if (connect(client, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("connect");
        return 1;
    }

    struct pollfd list[10];
    int list_len = 0;

    struct pollfd client_fd = {client, POLLIN, 0};
    insert_client(list, client_fd, &list_len);

    struct pollfd stdin_fd = {STDIN_FILENO, POLLIN, 0};
    insert_client(list, stdin_fd, &list_len);

    while (1) {
        int res = poll(list, list_len, -1);
        if (res == -1) {
            perror("poll");
            break;
        }

        for (int i = 0; i < list_len; i++) {
            if (list[i].revents & POLLIN) {
                if (list[i].fd == STDIN_FILENO) {
                    char buf[1024] = {0};
                    scanf("%s", buf);
                    int size = strlen(buf);
                    write(client, &size, 4);
                    write(client, buf, size);
                } else if (list[i].fd == client) {
                    int size = 0;
                    read(client, &size, 4);
                    char pack[1024] = {0};
                    read(client, pack, size);
                    printf("收到消息: %s\n", pack);
                }
            }
        }
    }
    close(client);
    return 0;
}

客户端2:

#include <head.h>
void* receive_message(void* arg) {
    int client = *(int*)arg;
    while (1) {
        int size = 0;
        int res = read(client, &size, 4);
        if (res == 0) {
            printf("与服务器断开连接\n");
            break;
        }
        char pack[1024] = {0};
        read(client, pack, size);
        printf("收到消息: %s\n", pack);
    }
    return NULL;
}

int main(int argc, const char *argv[]) {
    if (argc < 2) {
        printf("请输入端口号\n");
        return 1;
    }
    int port = atoi(argv[1]);

    // 创建客户端套接字
    int client = socket(AF_INET, SOCK_STREAM, 0);

    // 准备 ip 和 port
    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(192.168.126.235);

    if (connect(client, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("connect");
        return 1;
    }

    pthread_t thread_id;
    pthread_create(&thread_id, NULL, receive_message, &client);
    pthread_detach(thread_id);

    while (1) {
        char buf[1024] = {0};
        scanf("%s", buf);
        int size = strlen(buf);
        write(client, &size, 4);
        write(client, buf, size);
    }
    close(client);
    return 0;
}


http://www.kler.cn/a/593012.html

相关文章:

  • Java设计模式之享元模式
  • 【深度学习与大模型基础】第7章-特征分解与奇异值分解
  • Docker build 会在本地产生巨大的文件
  • vue3计算当前日期往前推一个月的日期,当前日期往前推7天
  • 用 C 语言理解封装、继承、多态
  • 单机 elasticsearch下载,安装,配置,启动,百度云链接提供
  • 技术视界 | 灵巧手的工作空间:解锁机器人精细操作的无限可能
  • PHP工程师转向Java开发定制的教材及教程信息,结合两种语言的差异点进行针对性推荐
  • 【计算机网络】2物理层
  • 群体智能优化算法-黏菌优化算法(Slime Mould Algorithm, SMA,含Matlab源代码)
  • vmware tools灰化
  • 如何排查和修复 MSSQL 数据库连接失败的问题
  • 【模拟】扫雷
  • 【机器学习】算法分类
  • Python个人学习笔记(18):模块(异常处理、traceback、日志记录)
  • 蓝桥杯备考:奶牛晒衣服
  • 【为什么游戏能使人上瘾】
  • FPGA中级项目5——VGA part1
  • ChatGPT推理模型通用模型大解析!
  • v-on=“$listeners“ 这个写法已经废弃了,如进行代替