day16-重构核心库、使用智能指针
太多了分一篇写。
5、EventLoop
这是一个事件轮询,在这个部分会通过Poller进行就绪事件的获取,并将事件进行处理。
头文件
这里使用了一个智能指针并使用的是unique_ptr指向Poller红黑树,防止所有权不止一个,也就是出现指针悬挂的问题。
class EventLoop {
public:
DISALLOW_COPY_AND_MOVE(EventLoop);
EventLoop();
~EventLoop();
void Loop() const;
void UpdateChannel(Channel *ch) const;
void DeleteChannel(Channel *ch) const;
private:
std::unique_ptr<Poller> poller_;
};
实现
这更像是一个中间件,通过初始化一个unique_ptr指针调用Poller中各种方法,由于使用了智能指针,析构函数为空,这是由于在超出作用域后poller_会自动释放。
通过Loop轮询处理将就绪事件链表中的事件进行处理,处理事件的方法在Channel中实现。
EventLoop::EventLoop() {
poller_ = std::make_unique<Poller>(); }
EventLoop::~EventLoop() {
}
void EventLoop::Loop() const {
while (true) {
for (Channel *active_ch : poller_->Poll()) {
active_ch->HandleEvent();
}
}
}
void EventLoop::UpdateChannel(Channel *ch) const {
poller_->UpdateChannel(ch); }
void EventLoop::DeleteChannel(Channel *ch) const {
poller_->DeleteChannel(ch); }
6、Acceptor
上述几个类处理了事件,但是建立连接只在Socket中出现过,这部分太底层了,我们需要开发更高级的接口,用来建立连接。
头文件
同样禁止了类的复制和移动,这里将构造函数设置为explicit目的是防止发生类似于这样的隐式类型转换:
EventLoop loop;
Acceptor acceptor = loop;
这个类中包含有socket、channel以及回调函数三个属性用以构建连接。这里使用unique_ptr来管理socket、channel属性。
class Acceptor {
public:
DISALLOW_COPY_AND_MOVE(Acceptor);
explicit Acceptor(EventLoop *loop);
~Acceptor();
RC AcceptConnection() const;
void set_new_connection_callback(std::function<void(int)> const &callback);
private:
std::unique_ptr<Socket> socket_;
std::unique_ptr<Channel> channel_;
std::function<void(int)> new_connection_callback_;
};
实现
在构造和析构函数中,首先创建指向socket的指针,之后开始调用创建、绑定、将socket设置为可监听的状态,然后构建channel并加入到轮询中,之后将AcceptConnection作为channel中的读回调函数并将通道事件置为可读。由于使用智能指针管理,因此析构函数为空。
Acceptor::Acceptor(EventLoop *loop) {
socket_ = std::make_unique<Socket>();
assert(socket_->Create() == RC_SUCCESS);
assert(socket_->Bind("127.0.0.1", 1234) == RC_SUCCESS);
assert(socket_->Listen() == RC_SUCCESS);
channel_ = std::make_unique<Channel>(socket_->fd(), loop);
std::function<void()> cb = std::bind(&Acceptor::AcceptConnection, this);
channel_->set_read_callback(cb);
channel_->EnableRead();
}
Acceptor::~Acceptor() {
}
将服务器与请求连接的客户端进行连接,并记录客户端的socket,将建立的连接设置为无阻塞状态,最后调用new_connection_callback_回调函数。
RC Acceptor::AcceptConnection() const{
int clnt_fd = -1;
if( socket_->Accept(clnt_fd) != RC_SUCCESS ) {
return RC_ACCEPTOR_ERROR;
}
// TODO: remove
fcntl(clnt_fd, F_SETFL, fcntl(clnt_fd, F_GETFL) | O_NONBLOCK); // 新接受到的连接设置为非阻塞式
if (new_connection_callback_) {
new_connection_callback_(clnt_fd);
}
return RC_SUCCESS;
}
set_new_connection_callback设置回调函数,在设置的过程中有个小细节就是利用std::move转移所有权,也就是callback变成了右值。
void Acceptor::set_new_connection_callback(std::function<void(int)> const &callback) {
new_connection_callback_ = std::move(callback);
}
7、Connection
Connection 类的主要任务是管理一个单一的网络连接。它封装了连接的各种操作和状态,提供了一种面向对象的方式来处理读写数据、维护连接状态以及处理事件,使得用户可以通过面向对象的方式来管理每一个连接,并且可以通过设置回调函数来处理连接建立、数据接收等事件。
头文件
提供了标志连接状态的标志位State,主要有socket、channel、buf、state、以及一些回调函数。可以通过这些属性看出来,在这个类中完成了所有连接上可能发生的事件。
class Connection {
public:
enum State {
Invalid = 0,
Connecting,
Connected,
Closed,
};
DISALLOW_COPY_AND_MOVE(Connection);
Connection(int fd, EventLoop *loop);
~Connection();
void set_delete_connection(std::function<void(int)> const &fn);
void set_on_connect(std::function<void(Connection *)> const &fn);
void set_on_recv(std::function<void(Connection *)> const &fn);
State state() const;
Socket *socket() const;
void set_send_buf(const char *str);
Buffer *read_buf();
Buffer *send_buf(

最低0.47元/天 解锁文章
4032

被折叠的 条评论
为什么被折叠?



