一、项目做的是什么
项目是通过在实现主从Reactor模型的one thread one EventLoop并发服务器组件:
其中主Reactor线程仅仅监控监听文件描述符,获取客户端新建立的链接,然后把获取到的新链接分发给从属Reactor进行通信事件的事件进行监控;
从Reactor线程负责客户端的通信事件的监控,I/O事件及业务事件的处理。
当前项目提供了HTPP协议组件。
1、什么是主从Reactor模型
Reactor模型是一种事件驱动机制,当有事件发生就去处理事件。
本项目是采用主从Reactor模型其中:
主Reactor线程就负责处理客户端的请求建立链接的请求,然后把成功建立的链接交给从Reactor线程;
从Reactor线程就监控这些成功建立的链接,看是否有事件触发,当事件触发就把任务分发给线程池处理;
线程池处理触发的任务事件。
二、SERVER模块
1、buffer模块
是什么?
buffer模块是一个缓冲区模块,用于实现接受和发送用户数据
class Buffer
{
private:
std::vector<char> _buffer;
uint64_t _reader_idx; // 读偏移
uint64_t _writer_idx; // 写偏移
}
用到了那些技术,是怎么实现的?
他的实现是通过一下线性数组实现的 ,数组默认大小是1024个字节(1KB,开发的日常习惯和经验,过大会造成资源的浪费,过小会频繁的申请内存,造成系统的开销增大)。
buffer模块可以进行字符串和buffer模块的读取和写入。
2、Socket模块
Socket模块 是什么?
这里主对socket 套接字的API进行封装,让我们更加简便的调用Socket套接字进行通信。
服务器和客户端创建套接字的流程是怎么样的
而客户端除了没有服务器调用accept接受,他有自己的connect进行连接请求
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
在TCP连接中,服务器如果突然断开连接,客户端会进行入TIME_WAIT状态,这时会占用port和ip,导致服务器重新连接失效,我们该如何解决?
在服务器端,可以设置SO_REUSEADDR
套接字选项,以允许在TIME_WAIT
状态下立即重用端口。这个选项告诉内核,即使之前的连接还处于TIME_WAIT
状态,也可以立即重用这个端口。
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)
通过调用什么接口,发送或者接受socket套接字的内容?
通过使用 send
和 recv
函数来发送和接收 socket 套接字的内容
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//flages为标志位通常啥子为0
3、Channel模块
Channel模块是什么?
对文件描述符进行I/O事件的进行管理,实现读,写,错误等事件的管理,在配合Poller模块对已经就绪的文件描述符,根据事件调用不同的会调函数
Channel模块的是怎么实现的?
下面是Channel类的成员变量
private:
int _fd;
EventLoop *_loop;
uint32_t _events; // 当前需要监视的事件 //_events:这个变量用于指定您感兴趣的事件
uint32_t _revents; // 当前连接触发事情 //_revents:这个变量用于标识实际发生的事件
using EventCallback = std::function<void()>; // 重新命名function<void()>;为 EventCallback,表示一个没有参数而且没有返回对象的函数对象
EventCallback _read_callback; // 可读事件被触发的回调函数
EventCallback _write_callback; // 可写事件被触发的回调函数
EventCallback _error_callback; // 错误事件被触发的回调函数
EventCallback _close_callback; // 连接断开事件被触发的回调函数
EventCallback _event_callback; // 任意事件被触发的回调函数
4、Poller模块
Poller模块什么?
对于poller模块主要是对epoll模型的封装,通过epoll_create创建句柄,epoll_ctl添加,修改和删除要监控的事件,epoll_wait等待就绪的事件,将就绪的事件添加到epoll_event结构体数组中去。
为什么要和Channel模块有关联?
因为_events事件触发后的各种回调函数,都保存在Channel中 ,就绪事件也是保存在Channel中的_events。所以我们要保存文件描述符和Channel的关系,这样才可以知道那个文件描述符,添加对那种事件的监控,怎么去处理就绪事件。
这里和Channl联系起了是通过unordered_map