Linux下epoll实现简单的C/S通信

夜色温柔 2024-11-25T10:04:12+08:00
0 0 160

简介

在Linux网络编程中,epoll是一种高效的I/O事件通知机制,可以监听多个I/O事件。在实现简单的C/S通信时,利用epoll可以实现服务器和客户端之间的异步通信。

epoll的基本原理

epoll是Linux特有的I/O事件通知机制,是通过在内核中维护一张红黑树和一个双向链表来实现的。它可以同时监听多个文件描述符上的事件,当有文件描述符上的事件满足条件时,就会通过回调函数通知应用程序。

epoll的基本原理如下:

  1. 创建一个epoll对象。
  2. 将需要监听的文件描述符添加到epoll对象中。
  3. 等待事件的发生。
  4. 若有事件发生,通过回调函数处理该事件。
  5. 回到第3步,继续等待事件的发生。

服务器端代码示例

下面是一个使用epoll实现简单的C/S通信的服务器端代码示例:

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

#define MAX_EVENTS 10
#define BUF_SIZE 1024

int main() {
    int server_sock, client_sock;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_addr_size;
    int str_len, i;
    char buf[BUF_SIZE];

    // 创建socket
    server_sock = socket(AF_INET, SOCK_STREAM, 0);
    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(1234);

    // 绑定socket
    bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
    // 监听socket
    listen(server_sock, 5);

    // 创建epoll对象
    int epoll_fd = epoll_create(MAX_EVENTS);
    struct epoll_event event;
    struct epoll_event* events = malloc(sizeof(struct epoll_event) * MAX_EVENTS);

    // 将服务器socket添加到epoll对象中
    event.events = EPOLLIN;
    event.data.fd = server_sock;
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_sock, &event);

    while (1) {
        // 等待事件的发生
        int event_cnt = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (event_cnt == -1) {
            perror("epoll_wait() error");
            break;
        }

        // 处理事件
        for (i = 0; i < event_cnt; ++i) {
            if (events[i].data.fd == server_sock) {
                // 有新的客户端连接请求
                client_addr_size = sizeof(client_addr);
                client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_addr_size);
                event.events = EPOLLIN;
                event.data.fd = client_sock;
                epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_sock, &event);
                printf("Connected client: %d\n", client_sock);
            } else {
                // 有客户端消息到达
                str_len = read(events[i].data.fd, buf, BUF_SIZE);
                if (str_len == 0) {
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
                    close(events[i].data.fd);
                } else {
                    write(events[i].data.fd, buf, str_len);
                }
            }
        }
    }

    // 关闭socket和epoll对象
    close(server_sock);
    close(epoll_fd);
    return 0;
}

客户端代码示例

下面是一个使用epoll实现简单的C/S通信的客户端代码示例:

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

#define MAX_EVENTS 10
#define BUF_SIZE 1024

int main() {
    int client_sock;
    struct sockaddr_in server_addr;
    socklen_t server_addr_size;
    int str_len, event_cnt, i;
    char buf[BUF_SIZE];

    // 创建socket
    client_sock = socket(AF_INET, SOCK_STREAM, 0);
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(1234);

    // 连接服务器
    if (connect(client_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("connect() error");
        exit(1);
    }

    // 创建epoll对象
    int epoll_fd = epoll_create(MAX_EVENTS);
    struct epoll_event event;
    struct epoll_event* events = malloc(sizeof(struct epoll_event) * MAX_EVENTS);

    // 将客户端socket添加到epoll对象中
    event.events = EPOLLIN;
    event.data.fd = client_sock;
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_sock, &event);

    while (1) {
        // 等待事件的发生
        event_cnt = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (event_cnt == -1) {
            perror("epoll_wait() error");
            break;
        }

        // 处理事件
        for (i = 0; i < event_cnt; ++i) {
            if (events[i].data.fd == client_sock) {
                // 服务器消息到达
                str_len = read(client_sock, buf, BUF_SIZE);
                if (str_len == 0) {
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_sock, NULL);
                    close(client_sock);
                } else {
                    printf("Server message: %s\n", buf);
                }
            }
        }
    }

    // 关闭socket和epoll对象
	close(client_sock);
	close(epoll_fd);
	return 0;
}

总结

通过使用epoll实现简单的C/S通信,我们可以实现服务器和客户端之间的异步通信。epoll是一种高效的I/O事件通知机制,可以同时监听多个I/O事件,当事件满足条件时通过回调函数进行处理。在实际的网络编程中,可以根据具体的需求灵活运用epoll来提高程序的性能和并发处理能力。

参考资料:

相似文章

    评论 (0)