文章目录
- 一、介绍
- [二、Reactor 服务器](#二、Reactor 服务器)
一、介绍
1、整体架构概述
这里实现的是一个基于 epoll + ET 边缘触发 的 Reactor 反应堆高性能服务器。
它是高并发网络编程的标准设计模式 ,专门用来处理海量连接、少量活跃的场景。
核心思想:
- 一个线程负责事件监听(epoll)
- 所有 IO 事件统一分发
- 每个连接自己处理读、写、异常
- 业务逻辑与网络框架完全解耦
二、Reactor 服务器
代码结构:
cpp
Mutex.hpp
Log.hpp
Common.hpp
InetAddr.hpp
Socket.hpp
Epoller.hpp
Connection.hpp
Reactor.hpp
Channel.hpp
Listener.hpp
NetCal.hpp
Main.cc
Client.cc
makefile
c
.PHONY:all
all:client reactorserver
reactorserver:Main.cc
g++ -o $@ $^ -ljsoncpp -std=c++17
client:Client.cc
g++ -o $@ $^ -ljsoncpp -std=c++17
.PHONY:clean
clean:
rm -f reactorserver client
1、基础工具模块
1)Mutex.hpp
cpp
#pragma once
#include <iostream>
#include <pthread.h>
namespace MutexModule
{
// 互斥锁封装类
class Mutex
{
public:
// 初始化锁
Mutex()
{
pthread_mutex_init(&_mutex, nullptr);
}
// 加锁
void Lock()
{
int n = pthread_mutex_lock(&_mutex);
}
// 解锁
void Unlock()
{
int n = pthread_mutex_unlock(&_mutex);
}
// 获取锁指针
pthread_mutex_t *Get()
{
return &_mutex;
}
// 销毁锁
~Mutex()
{
pthread_mutex_destroy(&_mutex);
}
private:
pthread_mutex_t _mutex;
};
// RAII 自动加解锁
class LockGuard
{
public:
LockGuard(Mutex &mutex) : _mutex(mutex)
{
_mutex.Lock(); // 构造时加锁
}
~LockGuard()
{
_mutex.Unlock(); // 析构时解锁
}
private:
Mutex &_mutex;
};
}
2)Log.hpp
cpp
#pragma once
#include <iostream>
#include <cstdio>
#include <string>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <memory>
#include <ctime>
#include <sys/types.h>
#include <unistd.h>
#include "Mutex.hpp"
namespace LogModule
{
using namespace MutexModule;
const std::string gsep = "\r\n";
// 日志策略基类(接口)
class LogStrategy
{
public:
~LogStrategy() = default;
virtual void SyncLog(const std::string &message) = 0;
};
// 控制台日志输出(线程安全)
class ConsoleLogStrategy : public LogStrategy
{
public:
void SyncLog(const std::string &message) override
{
LockGuard lockguard(_mutex);
std::cout << message << gsep;
}
~ConsoleLogStrategy() {}
private:
Mutex _mutex;
};
const std::string defaultpath = "./log/"; // /var/log
const std::string defaultfile = "my.log";
// 文件日志输出(自动建目录、线程安全)
class FileLogStrategy : public LogStrategy
{
public:
FileLogStrategy(const std::string &path = defaultpath, const std::string &file = defaultfile)
: _path(path), _file(file)
{
LockGuard lockguard(_mutex);
if (std::filesystem::exists(_path))
return;
try
{
std::filesystem::create_directories(_path);
}
catch (const std::filesystem::filesystem_error &e)
{
std::cerr << e.what() << std::endl;
}
}
// 追加写入日志文件
void SyncLog(const std::string &message) override
{
LockGuard lockguard(_mutex);
std::string filename = _path + (_path.back() == '/' ? "" : "/") + _file;
std::ofstream out(filename, std::ios::app);
if (!out.is_open())
return;
out << message << gsep;
out.close();
}
private:
std::string _path;
std::string _file;
Mutex _mutex;
};
// 日志等级类
enum class LogLevel
{
DEBUG,
INFO,
WARNING,
ERROR,
FATAL
};
// 日志等级转字符串
std::string LevelStr(LogLevel level)
{
switch (level)
{
case LogLevel::DEBUG:
return "DEBUG";
case LogLevel::INFO:
return "INFO";
case LogLevel::WARNING:
return "WARNING";
case LogLevel::ERROR:
return "ERROR";
case LogLevel::FATAL:
return "FATAL";
default:
return "UNKNOWN";
}
}
// 获取格式化时间字符串(线程安全)
std::string GetTimeStamp()
{
time_t curr = time(nullptr);
struct tm curr_tm; // 出参
localtime_r(&curr, &curr_tm);
char buf[128]; // 出参
snprintf(buf, sizeof(buf), "%4d-%02d-%02d %02d:%02d:%02d",
curr_tm.tm_year + 1900,
curr_tm.tm_mon + 1,
curr_tm.tm_mday,
curr_tm.tm_hour,
curr_tm.tm_min,
curr_tm.tm_sec);
return buf;
}
// 日志核心管理类
class Logger
{
public:
Logger()
{
EnableConsoleLogStrategy();
}
// 切换为文件输出
void EnableFileLogStrategy()
{
_fflush_strategy = std::make_unique<FileLogStrategy>();
}
// 切换为控制台输出
void EnableConsoleLogStrategy()
{
_fflush_strategy = std::make_unique<ConsoleLogStrategy>();
}
// 日志消息构造: 负责拼接内容, 析构时自动输出
class LogMessage
{
public:
// 构造日志头部(时间、等级、进程ID、文件名、行号)
LogMessage(LogLevel level, std::string src_name, int line_number, Logger &logger)
: _logger(logger)
{
std::stringstream ss;
ss << "[" << GetTimeStamp() << "] "
<< "[" << LevelStr(level) << "] "
<< "[" << getpid() << "] "
<< "[" << src_name << "] "
<< "[" << line_number << "] - ";
_loginfo = ss.str();
}
// 流方式拼接日志内容
template <typename T>
LogMessage &operator<<(const T &info)
{
std::stringstream ss;
ss << info;
_loginfo += ss.str();
return *this;
}
// 析构自动输出日志
~LogMessage()
{
if (_logger._fflush_strategy)
{
_logger._fflush_strategy->SyncLog(_loginfo);
}
}
private:
std::string _loginfo;
Logger &_logger;
};
// 仿函数接口, 创建日志消息
LogMessage operator()(LogLevel level, std::string name, int line)
{
return LogMessage(level, name, line, *this);
}
private:
std::unique_ptr<LogStrategy> _fflush_strategy;
};
Logger logger;
// 简化调用宏
#define LOG(level) logger(level, __FILE__, __LINE__)
#define Enable_Console_Log_Strategy() logger.EnableConsoleLogStrategy()
#define Enable_File_Log_Strategy() logger.EnableFileLogStrategy()
}
3)Common.hpp
cpp
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <fcntl.h>
// 程序退出状态码枚举
enum ExitCode
{
OK = 0, // 正常
USAGE_ERR, // 参数错误
SOCKET_ERR, // Socket 创建失败
BIND_ERR, // 绑定失败
LISTEN_ERR, // 监听失败
CONNECT_ERR, // 连接失败
FORK_ERR, // 进程创建失败
OPEN_ERR, // 打开文件失败
EPOLL_CREATE_ERR, // epoll创建失败
EPOLL_CTL_ERR // epoll控制失败
};
// 禁止拷贝基类(继承后无法拷贝/赋值)
class NoCopy
{
public:
NoCopy() {}
~NoCopy() {}
NoCopy(const NoCopy &) = delete;
NoCopy &operator=(const NoCopy &) = delete;
};
// 地址类型转换: sockaddr_in → sockaddr*
#define CONV(addr) ((struct sockaddr *)&addr)
int defaultport = 8080; // 默认端口
// 设置fd为非阻塞
void SetNonBlock(int fd)
{
int f1 = fcntl(fd, F_GETFL);
if (f1 < 0)
{
return;
}
fcntl(fd, F_SETFL, f1 | O_NONBLOCK);
}
// 非阻塞accept返回状态
#define ACCEPT_ERR -1 // 错误
#define ACCEPT_CONTINUE -2 // 继续
#define ACCEPT_DONE -3 // 完成
4)InetAddr.hpp
cpp
#pragma once
#include "Common.hpp"
// IPv4地址封装: 主机格式 <-> 网络格式
class InetAddr
{
public:
// 默认构造
InetAddr() {}
// 构造: 网络地址 -> 主机格式
InetAddr(struct sockaddr_in &addr)
: _addr(addr)
{
_port = ntohs(_addr.sin_port); // port
char ipbuffer[64]; // ip
inet_ntop(AF_INET, &_addr.sin_addr, ipbuffer, sizeof(ipbuffer));
_ip = ipbuffer;
}
// 构造:指定IP+端口 → 网络格式
InetAddr(const std::string &ip, uint16_t port)
: _ip(ip), _port(port)
{
memset(&_addr, 0, sizeof(_addr));
_addr.sin_family = AF_INET;
inet_pton(AF_INET, _ip.c_str(), &_addr.sin_addr); // ip
_addr.sin_port = htons(_port); // port
}
// 构造:仅端口, 绑定本机所有IP
InetAddr(uint16_t port)
: _port(port), _ip()
{
memset(&_addr, 0, sizeof(_addr));
_addr.sin_family = AF_INET;
_addr.sin_addr.s_addr = INADDR_ANY; // ip
_addr.sin_port = htons(_port); // port
}
// 设置网络地址信息
void SetAddr(struct sockaddr_in &addr)
{
_addr = addr;
_port = ntohs(_addr.sin_port);
char ipbuffer[64];
inet_ntop(AF_INET, &_addr.sin_addr, ipbuffer, sizeof(ipbuffer));
_ip = ipbuffer;
}
// 获取点分十进制IP
std::string Ip() { return _ip; }
// 获取主机字节序端口
uint16_t Port() { return _port; }
// 获取原生网络地址结构体
const struct sockaddr_in &NetAddr() { return _addr; }
// 获取通用地址指针(用于系统调用)
const struct sockaddr *NetAddrPtr() { return CONV(_addr); }
// 获取地址长度
socklen_t NetAddrLen() { return sizeof(_addr); }
// 比较两个地址是否相同
bool operator==(const InetAddr &addr)
{
return addr._ip == _ip && addr._port == _port;
}
// 转为 ip:port 格式字符串
std::string StringAddr()
{
return _ip + ":" + std::to_string(_port);
}
~InetAddr() {}
private:
struct sockaddr_in _addr; // 网络字节序地址
std::string _ip; // 点分十进制IP
uint16_t _port; // 主机字节序端口
};
2、网络核心模块
1)Socket.hpp
cpp
#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <cstdlib>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"
namespace SocketModule
{
using namespace LogModule;
const static int gbacklog = 16; // 监听队列长度
// 抽象Socket接口(模板方法)
class Socket
{
public:
virtual ~Socket() {}
virtual void SocketOrDie() = 0; // 创建socket
virtual void BindOrDie(uint16_t port) = 0; // 绑定端口
virtual void ListenOrDie(int backlog) = 0; // 监听
virtual std::shared_ptr<Socket> Accept(InetAddr *client) = 0; // 接收连接
virtual void Close() = 0; // 关闭socket
virtual int Recv(std::string *out) = 0; // 接收数据
virtual int Send(const std::string &message) = 0; // 发送数据
virtual int Connect(const std::string &server_ip, uint16_t port) = 0; // 连接服务端
virtual int Fd() = 0; // 获取文件描述符
public:
// 构建TCP服务端
void BuildTcpSocketMethod(uint16_t port, int backlog = gbacklog)
{
SocketOrDie();
BindOrDie(port);
ListenOrDie(backlog);
}
// 构建TCP客户端
void BuildTcpClientSocketMethod()
{
SocketOrDie();
}
};
const static int defaultfd = -1;
// TCP套接字实现
class TcpSocket : public Socket
{
public:
TcpSocket() : _sockfd(defaultfd) {}
TcpSocket(int fd) : _sockfd(fd) {}
~TcpSocket() {}
// 创建socket
void SocketOrDie() override
{
_sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
if (_sockfd < 0)
{
LOG(LogLevel::FATAL) << "socket error";
exit(SOCKET_ERR);
}
LOG(LogLevel::INFO) << "socket success";
}
// 绑定端口
void BindOrDie(uint16_t port) override
{
InetAddr localaddr(port);
int n = ::bind(_sockfd, localaddr.NetAddrPtr(), localaddr.NetAddrLen());
if (n < 0)
{
LOG(LogLevel::FATAL) << "bind error";
exit(BIND_ERR);
}
LOG(LogLevel::INFO) << "bind success";
}
// 监听
void ListenOrDie(int backlog) override
{
int n = ::listen(_sockfd, backlog);
if (n < 0)
{
LOG(LogLevel::FATAL) << "listen error";
exit(LISTEN_ERR);
}
LOG(LogLevel::INFO) << "listen success";
}
// 接收客户端连接
std::shared_ptr<Socket> Accept(InetAddr *client) override
{
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
// 阻塞等待客户端连接
int fd = ::accept(_sockfd, CONV(peer), &len);
if (fd < 0)
{
LOG(LogLevel::WARNING) << "accept warning ...";
return nullptr;
}
// 保存客户端地址
client->SetAddr(peer);
// 返回新连接的socket对象
return std::make_shared<TcpSocket>(fd);
}
// 接收数据 出参out
int Recv(std::string *out) override
{
char buffer[1024];
ssize_t n = ::recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
if (n > 0)
{
buffer[n] = 0;
*out += buffer;
}
return n;
}
// 发送数据
int Send(const std::string &message) override
{
return send(_sockfd, message.c_str(), message.size(), 0);
}
// 连接服务端
int Connect(const std::string &server_ip, uint16_t port) override
{
InetAddr server(server_ip, port);
return ::connect(_sockfd, server.NetAddrPtr(), server.NetAddrLen());
}
// 关闭套接字
void Close() override
{
if (_sockfd >= 0)
::close(_sockfd);
}
// 获取文件描述符
int Fd() override
{
return _sockfd;
}
private:
int _sockfd; // socket文件描述符
};
}
2)Epoller.hpp
cpp
#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/epoll.h>
#include "Log.hpp"
#include "Common.hpp"
using namespace LogModule;
// Epoll 封装类: 统一管理创建、增删改事件、等待
class Epoller
{
public:
// 构造: 创建 epoll 实例
Epoller() : _epfd(-1)
{
_epfd = epoll_create(128);
if (_epfd < 0)
{
LOG(LogLevel::FATAL) << "epoll_create error!!!";
exit(EPOLL_CREATE_ERR);
}
LOG(LogLevel::INFO) << "epoll_create success: " << _epfd;
}
// 事件操作辅助函数: 增/删/改
void ModEventHelper(int sockfd, uint32_t events, int oper)
{
struct epoll_event ev;
ev.events = events;
ev.data.fd = sockfd;
int n = epoll_ctl(_epfd, oper, sockfd, &ev);
if (n < 0)
{
LOG(LogLevel::ERROR) << "epoll_ctl error";
return;
}
LOG(LogLevel::INFO) << "epoll_ctl success: " << sockfd;
}
// 添加事件
void AddEvent(int sockfd, uint32_t events)
{
ModEventHelper(sockfd, events, EPOLL_CTL_ADD);
}
// 删除事件
void DelEvent(int sockfd)
{
int n = epoll_ctl(sockfd, EPOLL_CTL_DEL, sockfd, nullptr);
}
// 修改事件
void ModEvent(int sockfd, uint32_t events)
{
ModEventHelper(sockfd, events, EPOLL_CTL_MOD);
}
// 等待事件就绪
int WaitEvents(struct epoll_event revs[], int maxnum, int timeout)
{
int n = epoll_wait(_epfd, revs, maxnum, timeout);
if (n < 0)
LOG(LogLevel::WARNING) << "epoll_wait error";
else if (n == 0)
LOG(LogLevel::WARNING) << "epoll_wait timeout";
return n;
}
// 析构:关闭 epoll fd
~Epoller()
{
if (_epfd >= 0)
close(_epfd);
}
private:
int _epfd; // epoll 文件描述符
};
3)Connection.hpp
cpp
#pragma once
#include <iostream>
#include <string>
#include <functional>
#include "InetAddr.hpp"
class Reactor;
// 业务回调函数类型: 处理客户端消息
using handler_t = std::function<std::string(std::string &)>;
// 连接基类: 封装 fd + 事件 + 回调
class Connection
{
public:
Connection()
: _events(0),
_owner(nullptr)
{
}
// 设置监听事件
void SetEvent(const uint32_t &events)
{
_events = events;
}
// 获取监听事件
uint32_t GetEvent()
{
return _events;
}
// 设置所属 Reactor
void SetOwner(Reactor *owner)
{
_owner = owner;
}
// 获取所属 Reactor
Reactor *GetOwner()
{
return _owner;
}
// 注册业务回调
void RegisterHandler(handler_t handler)
{
_handler = handler;
}
// 纯虚函数: 子类必须实现
virtual void Recver() = 0; // 读事件处理
virtual void Sender() = 0; // 写事件处理
virtual void Excepter() = 0; // 异常处理
virtual int GetSockFd() = 0; // 获取套接字
~Connection()
{
}
public:
handler_t _handler; // 业务回调函数
private:
uint32_t _events; // 监听的事件类型
Reactor *_owner; // 所属反应堆
};
4)Reactor.hpp
cpp
#pragma once
#include <iostream>
#include <memory>
#include <unordered_map>
#include "Log.hpp"
#include "Epoller.hpp"
#include "Connection.hpp"
using namespace LogModule;
// Reactor 反应堆: 事件监听 + 分发 + 连接管理
class Reactor
{
static const int revs_num = 128;
private:
// 判断连接是否存在(内部)
bool IsConnectionExistsHelper(int sockfd)
{
auto iter = _connections.find(sockfd);
return iter != _connections.end();
}
// 判断连接是否存在(智能指针)
bool IsConnectionExists(const std::shared_ptr<Connection> &conn)
{
return IsConnectionExistsHelper(conn->GetSockFd());
}
// 判断连接是否存在(sockfd)
bool IsConnectionExists(int sockfd)
{
return IsConnectionExistsHelper(sockfd);
}
// 无连接
bool IsConnectionEmpty()
{
return _connections.empty();
}
// 等待一次就绪事件
int LoopOnce(int timeout)
{
return _epoller_ptr->WaitEvents(_revs, revs_num, timeout);
}
// 事件分发
void Dispatcher(int n)
{
for (int i = 0; i < n; i++)
{
int sockfd = _revs[i].data.fd;
uint32_t revents = _revs[i].events;
// 异常事件统一当读写处理
if (revents & EPOLLERR)
revents |= (EPOLLIN | EPOLLOUT);
if (revents & EPOLLHUP)
revents |= (EPOLLIN | EPOLLOUT);
// 读事件
if (revents & EPOLLIN && IsConnectionExists(sockfd))
_connections[sockfd]->Recver();
// 写事件
if (revents & EPOLLOUT && IsConnectionExists(sockfd))
_connections[sockfd]->Sender();
}
}
public:
Reactor()
: _epoller_ptr(std::make_unique<Epoller>()),
_isrunning(false)
{
}
// 主循环
void Loop()
{
if (IsConnectionEmpty())
return;
_isrunning = true;
int timeout = -1; // 永久非阻塞
while (_isrunning)
{
PrintConnection();
int n = LoopOnce(timeout);
Dispatcher(n);
}
_isrunning = false;
}
// 添加连接: 加入 epoll + 加入 map
void AddConnection(std::shared_ptr<Connection> &conn)
{
if (IsConnectionExists(conn))
{
LOG(LogLevel::WARNING) << "conn exists: " << conn->GetSockFd();
return;
}
// 加入 epoll
uint32_t events = conn->GetEvent();
int sockfd = conn->GetSockFd();
_epoller_ptr->AddEvent(sockfd, events);
// 设置所属 Reactor
conn->SetOwner(this);
// 加入管理 map
_connections[sockfd] = conn;
}
// 动态开关读写事件
void EnableReadWrite(int sockfd, bool enableread, bool enablewrite)
{
if (!IsConnectionExists(sockfd))
{
LOG(LogLevel::WARNING) << "EnableReadWrite: conn not exists: " << sockfd;
return;
}
// 设置 ET + 读写事件
uint32_t new_event = EPOLLET;
if(enableread)
new_event |= EPOLLIN;
if(enableread)
new_event |= EPOLLOUT;
_connections[sockfd]->SetEvent(new_event);
_epoller_ptr->ModEvent(sockfd, new_event);
}
// 删除连接: 从epoll移除 + 关闭fd
void DelConnection(int sockfd)
{
_epoller_ptr->DelEvent(sockfd);
_connections.erase(sockfd);
close(sockfd);
LOG(LogLevel::INFO) << "client quit: " << sockfd;
}
// 停止反应堆
void Stop()
{
_isrunning = false;
}
// 打印当前管理的fd
void PrintConnection()
{
std::cout << "当前 Reactor 管理 fd: ";
for (auto &conn : _connections)
{
std::cout << conn.second->GetSockFd() << " ";
}
std::cout << "\r\n";
}
~Reactor()
{
}
private:
std::unique_ptr<Epoller> _epoller_ptr; // epoll 封装
bool _isrunning; // 运行状态
std::unordered_map<int, std::shared_ptr<Connection>> _connections; // 连接管理
struct epoll_event _revs[revs_num]; // 就绪事件数组
};
5)Channel.hpp
cpp
#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include "Log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"
#include "Connection.hpp"
using namespace LogModule;
#define SIZE 1024
// Channel: 客户端连接通道
// 负责:非阻塞读写 + 缓冲区管理 + 事件处理
class Channel : public Connection
{
public:
Channel(int sockfd, const InetAddr &client)
: _sockfd(sockfd),
_client_addr(client)
{
SetNonBlock(_sockfd); // ET模式必须非阻塞
}
// 读事件处理
void Recver() override
{
char buffer[SIZE];
while (true)
{
ssize_t n = recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
if (n > 0)
{
buffer[n] = 0;
_inbuffer += buffer; // 数据放入读缓冲区
}
else if (n == 0)
{
Excepter(); // 对端关闭
return;
}
else
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
break; // 数据读完
else if (errno == EINTR)
continue; // 被信号中断,重试
else
{
Excepter(); // 真正出错
return;
}
}
}
LOG(LogLevel::DEBUG) << "Channel: Inbuffer:\n"
<< _inbuffer;
// 调用业务回调, 生成响应
if (!_inbuffer.empty())
{
_outbuffer += _handler(_inbuffer);
}
// 有数据要发送,主动触发发送
if (!_outbuffer.empty())
{
Sender();
}
}
// 写事件处理
void Sender() override
{
while (true)
{
ssize_t n = send(_sockfd, _outbuffer.c_str(), _outbuffer.size(), 0);
if (n > 0)
{
_outbuffer.erase(0, n); // 移除已发送数据
if (_outbuffer.empty())
break;
}
else if (n == 0)
break;
else
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
break; // 发送缓冲区满,下次再发
if (errno == EINTR)
continue;
else
{
Excepter();
return;
}
}
}
// 根据缓冲区是否为空,动态开关写事件
if (!_outbuffer.empty())
GetOwner()->EnableReadWrite(_sockfd, true, true); // 监听写
else
GetOwner()->EnableReadWrite(_sockfd, true, false); // 关闭写
}
// 异常处理: 关闭连接
void Excepter() override
{
GetOwner()->DelConnection(_sockfd);
}
// 获取套接字
int GetSockFd() override
{
return _sockfd;
}
// 获取读缓冲区
std::string &Inbuffer()
{
return _inbuffer;
}
// 追加数据到写缓冲区
void AppendOutBuffer(const std::string &out)
{
_outbuffer += out;
}
~Channel()
{
}
private:
int _sockfd;
std::string _inbuffer; // 读缓冲区
std::string _outbuffer; // 写缓冲区
InetAddr _client_addr; // 客户端地址
};
6)Listener.hpp
cpp
#pragma once
#include <iostream>
#include <memory>
#include "Common.hpp"
#include "Socket.hpp"
#include "Epoller.hpp"
#include "Connection.hpp"
#include "Channel.hpp"
using namespace SocketModule;
// 监听接收器: 专门处理新连接
class Listener : public Connection
{
public:
Listener(int port = defaultport)
: _port(port),
_listensock(std::make_unique<TcpSocket>())
{
_listensock->BuildTcpSocketMethod(_port); // 创建监听套接字
SetEvent(EPOLLIN | EPOLLET); // ET模式监听读事件
SetNonBlock(_listensock->Fd()); // 设置非阻塞
}
~Listener()
{
}
// 读事件:处理新连接
void Recver() override
{
InetAddr client;
while (true)
{
std::shared_ptr<Socket> newsock = _listensock->Accept(&client);
if (!newsock)
return;
int sockfd = newsock->Fd();
if (sockfd == ACCEPT_ERR)
break;
if (sockfd == ACCEPT_CONTINUE)
continue;
if (sockfd == ACCEPT_DONE)
break;
// 建立新连接, 封装成 Channel
std::shared_ptr<Connection> conn = std::make_shared<Channel>(sockfd, client);
conn->SetEvent(EPOLLIN | EPOLLET);
if (_handler != nullptr)
conn->RegisterHandler(_handler);
// 加入 Reactor 管理
GetOwner()->AddConnection(conn);
}
}
// 监听套接字不需要写事件
void Sender() override
{
}
// 监听套接字异常处理
void Excepter() override
{
}
// 获取监听 fd
int GetSockFd() override
{
return _listensock->Fd();
}
private:
int _port; // 监听端口
std::unique_ptr<Socket> _listensock; // 监听套接字
};
3、协议与业务模块
1)Protocol.hpp
cpp
#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <functional>
#include <jsoncpp/json/json.h>
#include "Socket.hpp"
using namespace SocketModule;
// 请求类: 客户端 → 服务端
class Request
{
public:
Request() {}
Request(int x, int y, char oper)
: _x(x), _y(y), _oper(oper)
{
}
// 序列化:对象 → JSON
std::string Serialize()
{
Json::Value root;
root["x"] = _x;
root["y"] = _y;
root["oper"] = _oper;
Json::FastWriter writer;
return writer.write(root);
}
// 反序列化:JSON → 对象
bool Deserialize(std::string &in)
{
Json::Value root;
Json::Reader reader;
if (!reader.parse(in, root))
return false;
_x = root["x"].asInt();
_y = root["y"].asInt();
_oper = root["oper"].asInt();
return true;
}
int X() { return _x; }
int Y() { return _y; }
char Oper() { return _oper; }
~Request() {}
private:
int _x;
int _y;
char _oper;
};
// 响应类: 服务端 → 客户端
class Response
{
public:
Response() {}
Response(int result, int code)
: _result(result), _code(code)
{
}
// 序列化:对象 → JSON
std::string Serialize()
{
Json::Value root;
root["result"] = _result;
root["code"] = _code;
Json::FastWriter writer;
return writer.write(root);
}
// 反序列化:JSON → 对象
bool Deserialize(std::string &in)
{
Json::Value root;
Json::Reader reader;
if (!reader.parse(in, root))
return false;
_result = root["result"].asInt();
_code = root["code"].asInt();
return true;
}
void SetResult(int res) { _result = res; }
int GetResult() { return _result; }
void SetCode(int code) { _code = code; }
int GetCode() { return _code; }
void ShowResult()
{
std::cout << "计算结果是: " << _result << "[" << _code << "]" << std::endl;
}
~Response() {}
private:
int _result;
int _code; // 状态码
};
const std::string sep = "\r\n";
// 业务处理函数类型
using func_t = std::function<Response(Request &req)>;
// 协议处理: 粘包解决 + 编解码 + 收发报文
class Protocol
{
public:
Protocol() {}
Protocol(func_t func) : _func(func) {}
// 编码: 长度\r\n数据\r\n
std::string Encode(const std::string &jsonstr)
{
return std::to_string(jsonstr.size()) + sep + jsonstr + sep;
}
// 解码: 从缓冲区提取一个完整包
bool Decode(std::string &buffer, std::string *package)
{
ssize_t pos = buffer.find(sep); // 2
if (pos == std::string::npos)
return false;
int len = std::stoi(buffer.substr(0, pos)); // 50
int total = len + pos + 2 * sep.size();
if (buffer.size() < total)
return false;
*package = buffer.substr(pos + sep.size(), len);
buffer.erase(0, total);
return true;
}
// 服务端: 处理客户端请求
void GetRequest(std::shared_ptr<Socket> &sock, InetAddr &client)
{
std::string buffer;
while (true)
{
// 1. 读取客户端数据
int n = sock->Recv(&buffer);
if (n > 0)
{
// 2. 循环解析完整报文
std::string package;
while (Decode(buffer, &package))
{
// 3. 反序列化请求
LOG(LogLevel::DEBUG) << client.StringAddr() << " 请求: " << package;
Request req;
if (!req.Deserialize(package))
continue;
// 4. 执行业务逻辑
Response resp = _func(req);
// 5. 响应序列化 + 编码发送
sock->Send(Encode(resp.Serialize()));
}
}
else if (n == 0) // 客户端关闭连接
{
LOG(LogLevel::INFO) << "client: " << client.StringAddr() << " 退出";
break;
}
else // 读取错误
{
LOG(LogLevel::WARNING) << "client: " << client.StringAddr() << " 读取异常";
break;
}
}
}
// 客户端: 获取服务端响应
bool GetResponse(std::shared_ptr<Socket> &client, std::string &resp_buff, Response *resp)
{
while (true)
{
// 1. 读取服务端响应
int n = client->Recv(&resp_buff);
if (n > 0)
{
// 2. 循环解析完整报文
std::string package;
while (Decode(resp_buff, &package))
{
// 3. 反序列化响应
resp->Deserialize(package);
}
return true;
}
else if (n == 0) // 服务端关闭连接
{
std::cout << "server quit" << std::endl;
return false;
}
else // 读取错误
{
std::cout << "recv error" << std::endl;
return false;
}
}
}
// 客户端: 构建请求报文
std::string BuildRequestString(int x, int y, char oper)
{
Request req(x, y, oper);
std::string json = req.Serialize();
return Encode(json);
}
// 处理单个请求包
std::string Execute(std::string &package)
{
LOG(LogLevel::DEBUG) << "进入到protocol Execute begnin";
// 反序列化包
Request req;
if(!req.Deserialize(package))
return "";
// 执行业务计算
Response resp = _func(req);
// 序列化并编码(带长度头)
std::string send_str = Encode(resp.Serialize());
LOG(LogLevel::DEBUG) << "进入到protocol Execute end";
return send_str;
}
~Protocol() {}
private:
func_t _func;
};
2)NetCal.hpp
cpp
#pragma once
#include "Protocol.hpp"
#include <iostream>
// 计算器业务类
// 状态码:0成功 1除零 2模零 3非法运算符
class Cal
{
public:
// 执行计算
Response Execute(Request &req)
{
// 初始化响应: 结果默认0, 状态码默认0
Response resp(0, 0);
switch (req.Oper())
{
case '+':
resp.SetResult(req.X() + req.Y());
break;
case '-':
resp.SetResult(req.X() - req.Y());
break;
case '*':
resp.SetResult(req.X() * req.Y());
break;
case '/':
if (req.Y() == 0)
resp.SetCode(1);
else
resp.SetResult(req.X() / req.Y());
break;
case '%':
if (req.Y() == 0)
resp.SetCode(2);
else
resp.SetResult(req.X() % req.Y());
break;
default:
resp.SetCode(3);
break;
}
// 返回包含结果和状态码的响应对象
return resp;
}
};
3)Main.cc
cpp
#include <iostream>
#include <string>
#include "Log.hpp"
#include "Common.hpp"
#include "Reactor.hpp"
#include "Channel.hpp"
#include "Listener.hpp"
#include "Protocol.hpp"
#include "NetCal.hpp"
static void Usage(std::string proc)
{
std::cerr << "Usage: " << proc << " port\n";
}
// ./reactorserver port
int main(int argc, char *argv[])
{
if (argc != 2)
{
Usage(argv[0]);
exit(USAGE_ERR);
}
Enable_Console_Log_Strategy();
uint16_t port = std::stoi(argv[1]);
// 计算器业务
std::shared_ptr<Cal> cal = std::make_shared<Cal>();
// 协议模块
std::shared_ptr<Protocol> protocol = std::make_shared<Protocol>([&](Request &req)
{ return cal->Execute(req); });
// 监听连接
std::shared_ptr<Connection> listener = std::make_shared<Listener>(port);
listener->RegisterHandler([&](std::string &inbuffer) -> std::string
{
LOG(LogLevel::DEBUG) << "业务回调开始";
std::string response_str;
std::string package;
// 循环解析并处理包
while(true)
{
if(!protocol->Decode(inbuffer,&package))
break;
response_str += protocol->Execute(package);
}
LOG(LogLevel::DEBUG)<<"业务回调结束, 返回: \n"<<response_str;
return response_str; });
// 启动 Reactor 服务器
std::unique_ptr<Reactor> reactor = std::make_unique<Reactor>();
reactor->AddConnection(listener);
reactor->Loop();
return 0;
}
4)Client.cc
cpp
#include <iostream>
#include <string>
#include <memory>
#include "Common.hpp"
#include "Socket.hpp"
#include "Protocol.hpp"
using namespace SocketModule;
void Usage(std::string proc)
{
std::cerr << "Usage: " << proc << " server_ip server_port" << std::endl;
}
// 从控制台读取数据
void GetDaTaFromStdin(int *x, int *y, char *oper)
{
std::cout << "Please Enter x: ";
std::cin >> *x;
std::cout << "Please Enter y: ";
std::cin >> *y;
std::cout << "Please Enter oper: ";
std::cin >> *oper;
}
// ./client server_ip server_port
int main(int argc, char *argv[])
{
if (argc != 3)
{
Usage(argv[0]);
exit(USAGE_ERR);
}
std::string server_ip = argv[1];
uint16_t server_port = std::stoi(argv[2]);
// 1. 创建客户端socket
std::shared_ptr<Socket> client = std::make_shared<TcpSocket>();
client->BuildTcpClientSocketMethod();
// 2. 连接服务器
if (client->Connect(server_ip, server_port) != 0)
{
std::cerr << "connect error" << std::endl;
exit(CONNECT_ERR);
}
// 3. 协议处理
std::unique_ptr<Protocol> protocol = std::make_unique<Protocol>();
std::string resp_buffer;
// 4. 循环交互
while (true)
{
int x, y;
char oper;
GetDaTaFromStdin(&x, &y, &oper);
// 构建并发送请求
std::string req_str = protocol->BuildRequestString(x, y, oper);
client->Send(req_str);
// 接收并解析响应
Response resp;
if (!protocol->GetResponse(client, resp_buffer, &resp))
break;
resp.ShowResult();
}
// 5. 关闭连接
client->Close();
return 0;
}
客户端

服务端
