在上文中,主要介绍了相关的类,本文介绍相关流程。
连接相关的流程介绍
Server端监听和接受连接的过程
这段代码来自 src/test/msgr/perf_msgr_server.cc,主要用于建立Server端的msgr:
void start() {
entity_addr_t addr;
addr.parse(bindaddr.c_str());
msgr->bind(addr);
msgr->add_dispatcher_head(&dispatcher);
msgr->start();
msgr->wait();
}
上面的代码是典型的服务端的启动流程:
- 绑定服务端地址 msgr->bind(addr)
- 添加消息分发类型 dispatcher
- 启动 msgr->start()
下面从内部具体如何实现。
- 调用processor的bind 函数,对于PosixStack, 只需要一个porcessor就可以了。
int AsyncMessenger::bind(const entity_addr_t &bind_addr)
{
......
for (auto &&p : processors) {
int r = p->bind(bind_addr, avoid_ports, &bound_addr);
}
......
}
int Processor::bind(const entity_addr_t &bind_addr,
const set<int>& avoid_ports,
entity_addr_t* bound_addr)
{
...
//向Processor对于的工作者线程 投递外部事件,其回调函数为 worker的 listen函数
worker->center.submit_to(worker->center.get_id(), [this, &listen_addr, &opts, &r]() {
r = worker->listen(listen_addr, opts, &listen_socket);
}, false);
...
}
当该外部事件被worker线程调度执行后,worker->listen完成了该Processor的listen_socket的创建。
- 添加 dispatcher
void add_dispatcher_head(Dispatcher *d) {
if (first)
ready();
}
在ready 函数里调用了Processor::start函数
void AsyncMessenger::ready()
{
ldout(cct,10) << __func__ << " " << get_myaddr() << dendl;
stack->start();
Mutex::Locker l(lock);
for (auto &&p : processors)
p->start();
dispatch_queue.start();
}
在Processor::start函数里,向EventCenter 投递了外部事件,该外部事件的回调函数里实现了向 EventCenter注册listen socket 的读事件监听。 该事件的处理函数为 listen_handeler
void Processor::start()
{
ldout(msgr->cct, 1) << __func__ << dendl;
// start thread
if (listen_socket) {
worker->center.submit_to(worker->center.get_id(), [this]() {
worker->center.create_file_event(
listen_socket.fd(), EVENT_READABLE, listen_handler);
}, false);
}
}
listen_handler对应的 处理函数为 processor::accept函数,其处理接收连接的事件。
class Processor::C_processor_accept : public EventCallback {
Processor *pro;
public:
explicit C_processor_accept(Processor *p): pro(p) {}
void do_request(int id) {
pro->accept();
}
};
void Processor::accept()
{
......
if (!msgr->get_stack()->support_local_listen_table())
w = msgr->get_stack()->get_worker();
int r = listen_socket.accept(&cli_socket, opts, &addr, w);
if (r == 0) {
msgr->add_accept(w, std::move(cli_socket), addr);
continue;
}
}
在函数Processor::accept里, 首先获取了一个worker,通过调用accept函数接收该连接。并调用 msgr->add_accept 函数。
void AsyncMessenger::add_accept(Worker *w,
ConnectedSocket cli_socket,
entity_addr_t &addr)
{
lock.Lock();
//创建连接,该Connection已经指定了 worker处理该Connection上所有的事件。
AsyncConnectionRef conn = new AsyncConnection(cct, this, &dispatch_queue, w);
conn->accept(std::move(cli_socket), addr);
accepting_conns.insert(conn);
lock.Unlock();
}
Client端主动连接的过程
AsyncConnectionRef AsyncMessenger::create_connect(const entity_addr_t& addr, int type)
{
// 获取一个 worker,根据负载均衡
Worker *w = stack->get_worker();
//创建Connection
AsyncConnectionRef conn = new AsyncConnection(cct, this, &dispatch_queue, w);
//
conn->connect(addr, type);
//添加到conns列表中
conns[addr] = conn;
return conn;
}
void AsyncConnection::_connect()
{
ldout(async_msgr->cct, 10) << __func__ << " csq=" << connect_seq << dendl;
state = STATE_CONNECTING;
// rescheduler connection in order to avoid lock dep
// may called by external thread(send_message)
center->dispatch_event_external(read_handler);
}
函数 AsyncConnection::_connect 设置了状态为 STATE_CONNECTING,向对应的 EventCenter投递 外部外部事件,其read_handler为 void AsyncConnection::process()函数。
void AsyncConnection::process()
{
......
default:
{
if (_process_connection() < 0)
goto fail;
break;
}
}
ssize_t AsyncConnection::_process_connection()
{
......
r = worker->connect(get_peer_addr(), opts, &cs);
if (r < 0)
goto fail;
center->create_file_event(cs.fd(), EVENT_READABLE, read_handler);
}
消息的接收和发送
消息的接收
消息的接收比较简单,因为消息的接收都是 内部事件,也就是都是由 epoll_wait触发的事件。其对应的回调函数 AsyncConnection::process() 去处理相应的接收事件。
消息的发送
消息的发送比较特殊,它涉及到外部事件和内部事件的相关的调用。
int AsyncConnection::send_message(Message *m){
......
//把消息添加到 内部发送队列里
out_q[m->get_priority()].emplace_back(std::move(bl), m);
//添加外部事件给对应的的CenterEvent,并触发外部事件
if (can_write != WriteStatus::REPLACING)
center->dispatch_event_external(write_handler);
}
发送相关的调用函数
void AsyncConnection::handle_write()
ssize_t AsyncConnection::write_message(Message *m,
bufferlist& bl, bool more)
ssize_t AsyncConnection::_try_send(bool more)
ssize_t AsyncConnection::_try_send(bool more)
{
......
if (!open_write && is_queued()) {
center->create_file_event(cs.fd(), EVENT_WRITABLE,
write_handler);
open_write = true;
}
if (open_write && !is_queued()) {
center->delete_file_event(cs.fd(), EVENT_WRITABLE);
open_write = false;
if (state_after_send != STATE_NONE)
center->dispatch_event_external(read_handler);
}
}
函数_try_send里比较关键的是:
- 当还有消息没有发送时, 就把该socket的 fd 添加到 EVENT_WRITABLE 事件中。
- 如果没有消息发送, 就把该 socket的 fd 的 EVENT_WRITABLE 事件监听删除
也就是当有发送请求时, 添加外部事件,并触发线程去处理发送事件。当外部事件一次可以完成发送消息的请求时,就不需要添加该fd对应的EVENT_WRITABLE 事件监听。当没有发送完消息时,就添加该fd的EVENT_WRITABLE 事件监听来触发内部事件去继续完成消息的发送。