epoll tcp server 演示收发消息

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

struct tcp_server_config {
    const char *ip = "127.0.0.1";
    int port = 12345;
    int backlog = 1024;
    int epoll_timeout = 5000;   // 5s
};
enum class tcp_server_error_code {
    SOCKET_NO_ERROR,
    SOCKET_CREATE_FAILED,
    SOCKET_BIND_FAILED
};
class epoll_tcp_server {
#define SAFE_DELETE_ARRAY(ptr) do { if (nullptr != ptr) { delete [] ptr; ptr = nullptr; } } while (0)
public:
    epoll_tcp_server() = default;
    epoll_tcp_server(const epoll_tcp_server &) = delete;
    epoll_tcp_server & operator = (const epoll_tcp_server &) = delete;
    virtual ~epoll_tcp_server() {
        close(sock_fd_);
        sock_fd_ = -1;
        close(epfd_);
        epfd_ = -1;
        SAFE_DELETE_ARRAY(events_);
    }
    bool init() {
        tcp_server_error_code ret_code = create_sock_fd();
        if (tcp_server_error_code::SOCKET_NO_ERROR != ret_code) {
            print_error_code(ret_code);
            return false;
        }
        if (false == create_epfd()) {
            return false;
        }
        if (false == epoll_add(sock_fd_)) {
            return false;
        }
        try {
            events_ = new struct epoll_event[fd_capacity_];
            memset(events_, 0x00, fd_capacity_ * sizeof(struct epoll_event));
        }
        catch (...) {
            std::cerr << "new struct epoll_event failed." << std::endl;
            return false;
        }
        init_succ = true;
        return true;
    }
    inline void set_config(const tcp_server_config &config) {
        config_ = config;
    }
    inline void set_fd_capacity(int cap) {
        fd_capacity_ = cap;
    }
    inline void set_buffer_size(int size) {
        buff_size_ = size;
    }
    virtual void tcp_message_process(const char *message, size_t size, std::string &output) {
        output.assign(message, size);
    }
    void run() {
        if (false == init_succ) {
            std::cerr << "epoll tcp server init failed." << std::endl;
            return;
        }
        while (true) {
            int event_num = epoll_wait(epfd_, events_, fd_capacity_, config_.epoll_timeout);
            if (event_num < 0) {
                std::cerr << "epoll_wait failed." << std::endl;
                break;
            }
            if (0 == event_num) {
                std::cerr << "epoll_wait timeout." << std::endl;
                continue;
            }
            run_core(event_num);
        }
    }
public:
    inline static void set_non_blocking(int fd) {
        int old_mode = fcntl(fd, F_GETFL);
        int new_mode = old_mode | O_NONBLOCK;
        fcntl(fd, F_SETFL, new_mode);
    }
private:
    tcp_server_error_code create_sock_fd() {
        sock_fd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (sock_fd_ < 0) {
            return tcp_server_error_code::SOCKET_CREATE_FAILED;
        }
        struct sockaddr_in saddr = {0};
        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(config_.port);
        saddr.sin_addr.s_addr = inet_addr(config_.ip);
        if (bind(sock_fd_, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
            return tcp_server_error_code::SOCKET_BIND_FAILED;
        }
        listen(sock_fd_, config_.backlog);
        return tcp_server_error_code::SOCKET_NO_ERROR;
    }
    inline bool create_epfd() {
        epfd_ = epoll_create(fd_capacity_);
        return epfd_ >= 0;
    }
    void print_error_code(tcp_server_error_code ret_code) {
        switch (ret_code) {
        case tcp_server_error_code::SOCKET_CREATE_FAILED:
            std::cerr << "epoll server socket create failed." << std::endl;
            break;
        case tcp_server_error_code::SOCKET_BIND_FAILED:
            std::cerr << "epoll server socket bind failed." << std::endl;
            break;
        }
    }
    inline bool epoll_add(int fd) {
        struct epoll_event ev = {0};
        ev.events = EPOLLIN | EPOLLET;
        ev.data.fd = fd;
        if (epoll_ctl(epfd_, EPOLL_CTL_ADD, fd, &ev) < 0) {
            std::cerr << "epoll_ctl add failed." << std::endl;
            return false;
        }
        return true;
    }
    inline bool epoll_del(int fd) {
        if (epoll_ctl(epfd_, EPOLL_CTL_DEL, fd, nullptr) < 0) {
            std::cerr << "epoll_ctl del failed." << std::endl;
            return false;
        }
        return true;
    }
    void accept_new_client() {
        struct sockaddr_in client_addr = { 0 };
        int len = sizeof(client_addr);
        int conn_fd = accept(sock_fd_, (struct sockaddr *)&client_addr, (socklen_t *)&len); 
        if (conn_fd < 0) {
            return;
        }
        std::cout << "connection fd = " << conn_fd << std::endl;
        epoll_add(conn_fd);        
    }
    void process_client_message(int fd) {
        char *buf = new (std::nothrow)char [buff_size_];
        if (nullptr == buf) {
            std::cerr << "new  tcp buffer failed." << std::endl;
            return;
        }
        memset(buf, 0x00, buff_size_);
        size_t len = recv(fd, buf, buff_size_, 0);
        if (0 == len) {
            epoll_del(fd);
            close(fd);
            std::cerr << "client fd = " << fd << " over." << std::endl;
            return;
        }
        std::cerr << "server recv buf = " << buf << std::endl;
        std::string output;
        tcp_message_process(buf, len, output);
        SAFE_DELETE_ARRAY(buf);
        send(fd, output.c_str(), output.size(), 0);
    }
    void run_core(int event_num) {
        int fd = -1; 
        for (int i = 0;i < event_num;i++) {
            fd = events_[i].data.fd;
            if (fd < 0) {
                continue;
            }
            if (!(events_[i].events & EPOLLIN)) {
                continue;
            }
            set_non_blocking(fd);
            if (fd == sock_fd_) {
                accept_new_client();
            }
            else {
                process_client_message(fd);
            }
        }
    }
private:
    int fd_capacity_ = 1024;
    int buff_size_ = 1024;
private:
    bool init_succ = false;
    tcp_server_config config_;
    int sock_fd_ = -1;
    int epfd_ = -1; 
    struct epoll_event *events_ = nullptr;
};
int main() {
    epoll_tcp_server tcp_server;
    if (false == tcp_server.init()) {
        return -1;
    }
    tcp_server.run();

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,你的问题是关于epoll客户端的收发,我会尽力回答。以下是一个基于epoll的客户端程序,可以实现收发功能: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/epoll.h> #define MAX_EVENTS 10 #define MAX_BUFFER_SIZE 1024 int main(int argc, char* argv[]) { if (argc != 3) { printf("usage: %s ip port\n", argv[0]); exit(1); } char* ip = argv[1]; int port = atoi(argv[2]); // 创建socket int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket error"); exit(1); } // 连接服务器 struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(ip); server_addr.sin_port = htons(port); if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("connect error"); exit(1); } // 创建epoll句柄 int epfd = epoll_create(MAX_EVENTS); if (epfd < 0) { perror("epoll_create error"); exit(1); } // 注册sockfd到epoll句柄中 struct epoll_event ev; ev.events = EPOLLIN | EPOLLET; ev.data.fd = sockfd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev) < 0) { perror("epoll_ctl error"); exit(1); } // 创建缓冲区 char buffer[MAX_BUFFER_SIZE]; while (1) { // 等待事件的发生 struct epoll_event events[MAX_EVENTS]; int n = epoll_wait(epfd, events, MAX_EVENTS, -1); if (n < 0) { perror("epoll_wait error"); exit(1); } // 处理发生的事件 for (int i = 0; i < n; i++) { if (events[i].data.fd == sockfd) { if (events[i].events & EPOLLIN) { // 接收数据 int len = recv(sockfd, buffer, MAX_BUFFER_SIZE, 0); if (len < 0) { perror("recv error"); exit(1); } else if (len == 0) { printf("server closed\n"); exit(1); } else { buffer[len] = '\0'; printf("received: %s", buffer); } } else if (events[i].events & EPOLLOUT) { // 发送数据 printf("input message: "); fgets(buffer, MAX_BUFFER_SIZE, stdin); int len = send(sockfd, buffer, strlen(buffer), 0); if (len < 0) { perror("send error"); exit(1); } } } } } // 关闭socket close(sockfd); return 0; } ``` 该程序使用了epoll实现IO多路复用,可以同时处理接收和发送数据的操作。在程序中,先创建了一个socket并连接到服务器,然后创建了一个epoll句柄,并将socket注册到epoll句柄中。接下来进入循环,等待事件的发生,并处理发生的事件。当socket可读时,接收数据并输出;当socket可写时,从标准输入中读取数据发送。当收到服务器关闭的消息时,程序退出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值