對應《GRPC-C++源碼分析(三)--main函數主要流程》中1.6節
這一節可能才是最核心的部分,包括大家理解的怎樣註冊listen和accept描述符,怎樣處理讀寫事件,怎樣處理業務邏輯等等。
由於這部分涉及的方面太多了,筆者也只是梳理出了核心的部分供參考,歡迎有精力的小夥伴繼續補充。
<code>server->Start(cqs_data, cqs_.size());/<code>
在Server::Start的實現中,主要分兩部分
<code>//第一部分
grpc_server_start(server_);/<code>
- 建立epoll,listen描述符註冊
<code> //第二部分
for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) {
(*it)->Start();
}/<code>
- accept描述符註冊,讀寫事件響應,處理註冊的service業務邏輯
下面對這兩部分分別進行解釋
1 grpc_server_start
在grpc_server_start函數中也分兩部分說明:
<code>//第一部分
for (i = 0; i < server->cq_count; i++) {
if (grpc_cq_can_listen(server->cqs[i])) {
server->pollsets[server->pollset_count++] =
grpc_cq_pollset(server->cqs[i]);
}
}/<code>
- 重點理解server->pollsets[server->pollset_count++]=grpc_cq_pollset(server->cqs[i]);看下圖
- 一句話,把cqs中的grpc_pollset指針放到grpc_server的指針數組pollsets中
<code>//第二部分
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(
start_listeners, server,
grpc_core::Executor::Scheduler(grpc_core::ExecutorJobType::SHORT)),
GRPC_ERROR_NONE);/<code>
- 這塊代碼對應了《GRPC-C++源碼分析(一)--網絡模型》中將start_listeners放入default-excutor線程中執行
- 跟蹤下grpc_core::Executor::Scheduler可以清晰看到最終調用的是grpc_closure_list_append方法
- 《GRPC-C++源碼分析(七)--bind&listen》中的server_start_listener在這裡被調用了
- 下面繼續看server_start_listener方法
1.1 server_start_listener
這個函數完成了epoll的創建,listen描述符的註冊
1.1-1
- server_start_listener最終調用的是tcp_server_start
- 分段解釋下tcp_server_start
<code>//tcp_server_posix.cc
static void tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollsets,
size_t pollset_count,
grpc_tcp_server_cb on_accept_cb,
void* on_accept_cb_arg) {
size_t i;
grpc_tcp_listener* sp;
GPR_ASSERT(on_accept_cb);
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->on_accept_cb);
GPR_ASSERT(s->active_ports == 0);
s->on_accept_cb = on_accept_cb;
s->on_accept_cb_arg = on_accept_cb_arg;
s->pollsets = pollsets;
s->pollset_count = pollset_count;
sp = s->head;/<code>
1.1-2
- 上圖沒有複雜東西,畫出來幫助理解賦值關係而已
- 注意右邊的active_pollable,後面繼續調用的grpc_pollset_add_fd方法,把創建epoll的描述符epfd放到了這裡
<code> for (i = 0; i < pollset_count; i++) {
grpc_pollset_add_fd(pollsets[i], sp->emfd);
}/<code>
1.1-3
- epoll的創建,描述符的註冊見上圖的藍色框
- epoll的描述符epfd保存在了1.1-2圖裡的pollable裡
<code> GRPC_CLOSURE_INIT(&sp->read_closure, on_read, sp,
grpc_schedule_on_exec_ctx);
grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);/<code>
- GRPC_CLOSURE_INIT簡單的理解為將on_read方法綁定在sp->read_closure中即可
- grpc_fd_notify_on_read的實現見1.1-4
1.1-4
- grpc_fd_notify_on_read設置完的東西,在1.1-4圖中粉色虛線框裡的fd_become_readable方法中使用
- 大體意思是將on_read方法綁定在sp->read_closure,然後將sp->read_closure再綁定在sp->emfd->read_closure裡。這些綁定會在後面的fd_become_readable中用到
閱讀更多 路小飯 的文章