7.14作业

实现2个客户端之间互相聊天

要求:服务器使用 select 模型实现接受多个客户端连接,以及转发消息;

客户端要求:使用 poll 模型解决 技能够 read 读取服务器发来的消息,又能够scanf读取键盘输入的信息;客户端服务器不允许开启额外线程和进程。

服务器

#include <head.h>

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};

    // 创建监听套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 设置套接字选项
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
                   &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8888);

    // 绑定地址
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    // 监听
    if (listen(server_fd, 100) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    fd_set read_fds;
    FD_ZERO(&read_fds);
    FD_SET(server_fd, &read_fds);
    int max_fd = server_fd;

    while (1) {
        fd_set temp_fds = read_fds;
        int activity = select(max_fd + 1, &temp_fds, NULL, NULL, NULL);

        if (activity < 0) {
            perror("select error");
            break;
        } else if (activity > 0) {
            if (FD_ISSET(server_fd, &temp_fds)) {
                // 新连接请求
                if ((new_socket = accept(server_fd,
                                         (struct sockaddr *)&address,
                                         (socklen_t *)&addrlen)) < 0) {
                    perror("accept");
                    continue;
                }
                FD_SET(new_socket, &read_fds);
                if (new_socket > max_fd) {
                    max_fd = new_socket;
                }
            } else {
                // 已有客户端发送消息
                for (int i = 0; i <= max_fd; i++) {
                    if (FD_ISSET(i, &temp_fds)) {
                        int valread = read(i, buffer, 1024);
                        if (valread == 0) {
                            // 客户端断开连接
                            close(i);
                            FD_CLR(i, &read_fds);
                        } else {
                            buffer[valread] = '\0';
                            // 转发消息给其他客户端
                            for (int j = 0; j <= max_fd; j++) {
                                if (j != server_fd && j != i && FD_ISSET(j, &read_fds)) {
                                    write(j, buffer, strlen(buffer));
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return 0;
}

客户端

#include <head.h>

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char buffer[1024] = {0};
    struct pollfd fds[2];

    // 创建套接字
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket creation error");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8888);

    // 将IP地址转换为网络字节序
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        perror("invalid address/ Address not supported");
        return -1;
    }

    // 连接到服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("connection failed");
        return -1;
    }

    fds[0].fd = 0;  // 标准输入
    fds[0].events = POLLIN;
    fds[1].fd = sock;
    fds[1].events = POLLIN;

    while (1) {
        int poll_result = poll(fds, 2, -1);
        if (poll_result < 0) {
            perror("poll error");
            break;
        } else if (poll_result > 0) {
            if (fds[0].revents & POLLIN) {
                // 键盘输入
                fgets(buffer, 1024, stdin);
                buffer[strcspn(buffer, "\n")] = '\0';
                send(sock, buffer, strlen(buffer), 0);
            }
            if (fds[1].revents & POLLIN) {
                // 服务器消息
                int valread = read(sock, buffer, 1024);
                if (valread == 0) {
                    // 服务器断开连接
                    printf("服务器断开连接\n");
                    break;
                } else {
                    buffer[valread] = '\0';
                    printf("已收到: %s\n", buffer);
                }
            }
        }
    }
    close(sock);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值