c语言编程笔录

您现在的位置是:首页 > C语言 > C#

C#

epoll多路复用的一个实例程序(C实现)

江奕云 2023-08-09C#
前言epoll是Linux内核提供的一种I/O事件通知机制,它可以用来监视多个文件描述符的I/O事件。与传统的select和poll函数相比,epoll具有更好的性能和扩展性

前言

epoll是Linux内核提供的一种I/O事件通知机制,它可以用来监视多个文件描述符的I/O事件。与传统的select和poll函数相比,epoll具有更好的性能和扩展性。本文将介绍一个使用epoll实现的多路复用实例程序,该程序使用C语言编写。

实现代码

下面是一个基于epoll的多路复用实例程序的代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAX_EVENTS 1024
#define BUF_SIZE 1024

int main() {
    int listen_sock, client_sock;
    struct sockaddr_in server_addr, client_addr;

    // 创建监听socket
    listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock == -1) {
        perror("socket");
        exit(1);
    }

    // 设置地址和端口
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(8080);

    // 绑定socket
    int ret = bind(listen_sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if (ret == -1) {
        perror("bind");
        exit(1);
    }

    // 开始监听
    ret = listen(listen_sock, 5);
    if (ret == -1) {
        perror("listen");
        exit(1);
    }

    // 创建epoll实例
    int epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        perror("epoll_create1");
        exit(1);
    }

    // 添加监听socket到epoll实例中
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = listen_sock;
    ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_sock, &event);
    if (ret == -1) {
        perror("epoll_ctl");
        exit(1);
    }

    struct epoll_event events[MAX_EVENTS];
    char buf[BUF_SIZE];

    while (1) {
        int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (num_events == -1) {
            perror("epoll_wait");
            exit(1);
        }

        for (int i = 0; i < num_events; i++) {
            int fd = events[i].data.fd;

            // 监听socket有新的连接请求
            if (fd == listen_sock) {
                socklen_t client_len = sizeof(client_addr);
                client_sock = accept(listen_sock, (struct sockaddr*)&client_addr, &client_len);
                if (client_sock == -1) {
                    perror("accept");
                    exit(1);
                }
                printf("New client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

                event.events = EPOLLIN | EPOLLET;
                event.data.fd = client_sock;
                ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_sock, &event);
                if (ret == -1) {
                    perror("epoll_ctl");
                    exit(1);
                }
            }
            // 客户端有数据可读
            else {
                memset(buf, 0, BUF_SIZE);
                ssize_t recv_size = recv(fd, buf, BUF_SIZE, 0);
                if (recv_size == -1) {
                    perror("recv");
                    exit(1);
                }
                if (recv_size == 0) {
                    printf("Client disconnected: %d\n", fd);
                    close(fd);
                    continue;
                }
                printf("Received data from client: %s\n", buf);

                // 这里可以对收到的数据进行处理

                ssize_t send_size = send(fd, buf, strlen(buf), 0);
                if (send_size == -1) {
                    perror("send");
                    exit(1);
                }
            }
        }
    }

    close(listen_sock);
    return 0;
}

代码解释

上述代码实现了一个简单的基于epoll的多路复用服务器。程序首先创建一个监听socket,然后绑定和启动监听。之后,程序创建一个epoll实例,并将监听socket添加到epoll实例中,用于监听新的连接请求。

在主循环中,程序调用epoll_wait函数来等待事件的发生。当有事件发生时,程序通过遍历events数组来处理每个事件。如果是监听socket上有新的连接请求,程序调用accept函数接受连接,并将新的客户端socket添加到epoll实例中。

如果是客户端有数据可读,程序调用recv函数读取数据,并对数据进行处理(这部分代码省略了处理逻辑)。然后,程序通过send函数将数据回送给客户端。

总结

通过使用epoll机制,我们可以实现高效且灵活的多路复用。这种方式可以有效地处理大量的并发连接,提高系统的性能。本文提供了一个简单的基于epoll的多路复用服务器示例程序,希望对您理解epoll的工作原理和用法有所帮助。

文章评论