一个人知道自己为什么而活,
就可以忍受任何一种生活。
— 尼采 —
✨✨✨项目地址在这里 ✨✨✨
✨✨✨https://gitee.com/penggli_2_0/TcpServer✨✨✨
仿mudou的高并发服务器
- 1 主从Reactor模型
- 2 基础功能封装
-
- 2.1 缓冲区 Buffer模块
- 2.2 通用类型 Any类
- 2.3 套接字 Socket模块
1 主从Reactor模型
这个项目的目标是实现一个可以高效处理请求的服务器,那么对于这样的一个服务器要如何实现呢?
这里采取主从Reactor模型的方案:
简单来说就是这样的一个模型: 其中管理连接的对象是Connection对象,这个类是高并发服务器的核心部分,这里包含了对套接字的处理,事件等待等一系列操作!而Connection对象中对于这些操作的管理也要通过其他的对象来进行!
主要的工作就是搭建起主从Reactor模型,但是这个模型不是一下子就可以写出来的。为了实现主从Reactor模型,我们先需要实现一些基础类,对基础功能进封装,然后对这些功能进行整合,最终实现主从Reactor模型!
2 基础功能封装
2.1 缓冲区 Buffer模块
Buffer模块是⼀个缓冲区模块,用于实现通信中用户态的接收缓冲区和发送缓冲区功能:
Buffer模块成员变量很简单:
- vector<char>容器_buffer: 对内存空间进行管理
- uint64_t _reader_idx 读偏移:进行读取位置在_buffer容器中的偏移量,即读取的起始位置。
- uint64_t _writer_idx 写偏移:下一次写入位置在_buffer容器中的偏移量,即写入的起始位置。
接下来实现一下基础功能:
// 缓冲区Buffer类
class Buffer
{
private:
std::vector<char> _buffer;
uint64_t _reader_idx;
uint64_t _writer_idx;
private:
char *Begin() {
return &*_buffer.begin(); }
public:
Buffer() : _buffer(BUFFER_DEFAULT_SIZE), _reader_idx(0), _writer_idx(0) {
}
// 获取当前写入起始地址
char *WritePos() {
return Begin() + _writer_idx; }
// 获取当前读取起始地址
char *ReadPos() {
return Begin() + _reader_idx; }
// 获取读取位置之前的空闲空间
uint64_t HeadIdleSize() {
return _reader_idx; }
// 获取写入位置之后的空闲空间
uint64_t TailIdleSize() {
return _buffer.size() – _writer_idx; }
// 获取可读数据大小
uint64_t ReadAbleSize() {
return _writer_idx – _reader_idx; }
// 读/写偏移移动
void MoveReadOffset(uint64_t len)
{
if (len <= 0)
return;
assert(len <= ReadAbleSize());
_reader_idx += len;
}
void MoveWriteOffset(uint64_t len)
{
if (len <= 0)
return;
assert(len <= TailIdleSize());
_writer_idx += len;
}
// 确保可写空间足够 — 整体空闲空间足够了就移动数据,否则进行扩容
void EnsureWriteSpace(uint64_t len)
{
// 当len小于写入位置之后的空闲空间 直接进行写入
if (len <= TailIdleSize())
{
return;
}
// len 小于总共的空闲空间
else if (len <= TailIdleSize() + HeadIdleSize())
{
// 记录总共的数据
uint64_t sz = ReadAbleSize();
// 移动数据
std::copy(ReadPos(), ReadPos() + sz, Begin());
// 更新写入读取位置
_reader_idx = 0;
_writer_idx = sz;
}
// 需要扩容
else
{
// 在写入位置之后扩充len个大小
_buffer.resize(_writer_idx + len);
}
}
// ———-写入数据————
void Write(const void *data, uint64_t len)
{
// 写入的数据不能超过可写的总空间
// 确保可以正常写入
EnsureWriteSpace(len);
// 进行拷贝
const char *d = reinterpret_cast<const char *>(data);
std::copy(d, d + len, WritePos());
}
// 写入Buffer
void WriteBuffer
评论前必须登录!
注册