一个简单的C语言编码示例,使用epoll实现一个简单的echo服务器,可以同时处理多个客户端连接

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>

#define MAX_EVENTS 10
#define BUF_SIZE 1024

int main(int argc, char *argv[]) {
    int listen_sock, conn_sock, epoll_fd, n;
    struct sockaddr_in serv_addr, cli_addr;
    socklen_t cli_len = sizeof(cli_addr);
    struct epoll_event ev, events[MAX_EVENTS];
    char buf[BUF_SIZE];

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

    // 绑定监听地址和端口
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(8888);
    if (bind(listen_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    // 开始监听
    if (listen(listen_sock, 5) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // 创建epoll实例
    epoll_fd = epoll_create1(0);
    if (epoll_fd < 0) {
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }

    // 将监听套接字添加到epoll监视集合中
    ev.events = EPOLLIN;
    ev.data.fd = listen_sock;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_sock, &ev) < 0) {
        perror("epoll_ctl: listen_sock");
        exit(EXIT_FAILURE);
    }

    // 进入主循环,等待事件发生
    while (1) {
        n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (n < 0) {
            perror("epoll_wait");
            exit(EXIT_FAILURE);
        }

        for (int i = 0; i < n; i++) {
            if (events[i].data.fd == listen_sock) {  // 监听套接字有连接请求
                conn_sock = accept(listen_sock, (struct sockaddr *)&cli_addr, &cli_len);
                if (conn_sock < 0) {
                    perror("accept");
                    exit(EXIT_FAILURE);
                }
                printf("Accepted connection from %s:%d\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));

                // 将新连接套接字添加到epoll监视集合中
                ev.events = EPOLLIN;
                ev.data.fd = conn_sock;
                if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_sock, &ev) < 0) {
                    perror("epoll_ctl: conn_sock");
                    exit(EXIT_FAILURE);
                }
            } else {  // 客户端套接字有数据可读
                int fd = events[i].data.fd;
                n = read(fd, buf, BUF_SIZE);
                if (n <= 0) {
                    close(fd);
                    printf("Connection closed\n");
                } else {
                    write(fd, buf, n);
                }
            }
        }
    }

    close(listen_sock);
    return 0;
}

例中使用epoll机制实现了一个基于事件驱动的并发服务器,它可以同时处理多个客户端连接。

在主循环中,程序调用epoll_wait函数等待事件发生。当有事件发生时,epoll_wait会返回一个包含所有发生事件的结构体数组events,我们遍历此数组并根据每个事件的类型进行相应的处理。

如果事件类型是EPOLLIN,表示对应的文件描述符上有数据可读;程序会读取数据并直接回显给客户端。如果事件类型是EPOLLOUT,表示对应的文件描述符可写;程序会将之前存储的数据发送给客户端。如果事件类型是EPOLLRDHUP或EPOLLHUP,表示对应的文件描述符已经断开连接;程序会关闭该套接字并从epoll监视集合中移除。如果事件类型是EPOLLERR,表示对应的文件描述符出现错误;程序也会关闭该套接字并从epoll监视集合中移除。

如果事件类型是EPOLLIN且对应的文件描述符是监听套接字,则表示有新的客户端连接请求;程序会接受新连接,并将其加入epoll监视集合。

总体来说,该程序通过epoll机制实现了高效的事件驱动并发服务器,避免了传统select和poll机制可能存在的性能问题。
————————————————
版权声明:本文为CSDN博主「逆风水手」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_21688871/article/details/129944924

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值