epoll tcp server 演示收发消息

mac2024-06-23  49

#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)