基于c++编写的tcp服务器epoll事件回调类

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

#include 
#include 
#include 
#include 

class TcpServer {
    using IOCallback = std::function<void(int, const std::string &)>;
    using Callback = std::function<void(int)>;

private:
    int port_;
    int server_fd_;
    int epoll_fd_;
    bool running_;
    int events_;
    IOCallback read_callback_;
    IOCallback write_callback_;
    Callback connect_callback_;
    Callback disconnect_callback_;

public:
    
    TcpServer(int port, int events = EPOLLIN, \
        IOCallback read_callback = NULL, \
        IOCallback write_callback = NULL, \
        Callback connect_callback = NULL, \
        Callback disconnect_callback = NULL) \
        : port_(port), events_(events), read_callback_(read_callback), write_callback_(write_callback) {}

    void set_server_port(int port) {
        port_ = port;
    } 

    void set_server_read_callback(IOCallback read_callback) {
        read_callback_ = read_callback;
    }

    void set_server_write_callback(IOCallback write_callback) {
        write_callback_ = write_callback;
    }

    void set_server_connect_callback(Callback connect_callback) {
        connect_callback_ = connect_callback;
    }

    void set_server_disconnect_callback(Callback disconnect_callback) {
        disconnect_callback_ = disconnect_callback;
    }

    // EPOLLIN(读事件、默认水平触发) | EPOLLOUT(写事件)| EPOLLET(边沿触发)
    void set_events(int events) {
        events_ = events;
    }

    void start() {
        struct sockaddr_in server_addr;
        server_fd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (server_fd_ == -1) {
            std::cerr << "Failed to create socket: " + std::string(strerror(errno)) << std::endl;
            return;
        }

        int opt = 1;
        if (setsockopt(server_fd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
            close(server_fd_);
            std::cerr << "Failed to set socket options: " + std::string(strerror(errno)) << std::endl;
            return;
        }

        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = INADDR_ANY;
        server_addr.sin_port = htons(port_);

        if (bind(server_fd_, (struct sockaddr *)(&server_addr), sizeof(server_addr)) == -1) {
            close(server_fd_);
            std::cerr << "Failed to bind socket: " + std::string(strerror(errno)) << std::endl;
            return;
        }

        if (listen(server_fd_, SOMAXCONN) == -1) {
            close(server_fd_);
            std::cerr << "Failed to listen on socket: " + std::string(strerror(errno)) << std::endl;
        }

        create_epoll();
        run();
    }

    void stop() {
        running_ = false;
    }

private:
    bool create_epoll() {
        epoll_fd_ = epoll_create1(0);
        if (epoll_fd_ == -1) {
            close(server_fd_);
            std::cerr << "Failed to create epoll: " + std::string(strerror(errno)) << std::endl;
            return false;
        }

        epoll_event event;
        event.events = EPOLLIN;
        event.data.fd = server_fd_;

        if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, server_fd_, &event) == -1) {
            close(epoll_fd_);
            close(server_fd_);
            std::cerr << "Failed to add server file descriptor to epoll: " + std::string(strerror(errno)) << std::endl;
            return false;
        }

        return true;
    }

    void run() {
        running_ = true;
        while (running_) {
            std::vector<epoll_event> events(1024);
            int num_events = epoll_wait(epoll_fd_, events.data(), static_cast<int>(events.size()), -1);
            if (num_events == -1) {
                if (errno == EINTR) {
                    continue;
                } else {
                    std::cerr << "Failed to wait on epoll: " + std::string(strerror(errno)) << std::endl;
                }
            }

            for (int i = 0; i < num_events; ++i) {
                if (events[i].data.fd == server_fd_) {
                    accept_connection();
                } else {
                    handle_event(events[i]);
                }
            }
        }

        close(epoll_fd_);
        close(server_fd_);
    }

    void accept_connection() {
        sockaddr_in client_addr;
        socklen_t client_addr_size = sizeof(client_addr);
        int client_fd = accept(server_fd_, reinterpret_cast<sockaddr *>(&client_addr), &client_addr_size);
        if (client_fd == -1) {
            std::cerr << "Failed to accept connection: " << strerror(errno) << std::endl;
            return;
        }

        int flags = fcntl(client_fd, F_GETFL, 0);
        if (flags == -1) {
            close(client_fd);
            std::cerr << "Failed to get client socket flags: " << strerror(errno) << std::endl;
            return;
        }

        if (fcntl(client_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
            close(client_fd);
            std::cerr << "Failed to set client socket to non-blocking: " << strerror(errno) << std::endl;
            return;
        }

        epoll_event event;
        event.events = events_;
        event.data.fd = client_fd;

        if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, client_fd, &event) == -1) {
            close(client_fd);
            std::cerr << "Failed to add client socket to epoll: " << strerror(errno) << std::endl;
            return;
        }

        connect_callback_(client_fd);
    }

    void handle_event(const epoll_event &event) {
        int client_fd = event.data.fd;
        if (event.events & EPOLLIN) {
            read_data(client_fd);
        }
        if (event.events & EPOLLOUT) {
            write_data(client_fd);
        }
        if (event.events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) {
            close(client_fd);

            disconnect_callback_(client_fd);
        }
    }

    void read_data(int client_fd) {
        std::string data;
        char buffer[1024];

        while (true) {
            ssize_t bytes_read = read(client_fd, buffer, sizeof(buffer));
            if (bytes_read == -1) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    break;
                } else {
                    std::cerr << "Failed to read from client socket: " << strerror(errno) << std::endl;
                    close(client_fd);
                    return;
                }
            } else if (bytes_read == 0) {
                break;
            } else {
                data.append(buffer, bytes_read);
            }
        }

        if (!data.empty()) {
            read_callback_(client_fd, data);
        }
    }

    void write_data(int client_fd) {
        write_callback_(client_fd, "");
    }
};

你可能感兴趣的:(网络编程,c++,tcp/ip,服务器)