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
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值