在上文中,主要介紹了相關的類,本文介紹相關流程。
連接相關的流程介紹
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 事件監聽來觸發內部事件去繼續完成消息的發送。