如果没有特殊喜好,推荐从example/cpp/helloworld/greeter_server.cc开始阅读。前期分析的是同步部分的代码。
1 BuildAndStart
ServerBuilder::BuildAndStart()是main线程一切的开端,这里会列出其中重要的代码段并简单阐述。
1.1 初始化ServerCompletionQueue
<code> std::shared_ptr<:vector>>>
sync_server_cqs(std::make_shared<
std::vector<:unique_ptr>>>());/<code>
…………
<code> if (has_sync_methods) {
grpc_cq_polling_type polling_type =
is_hybrid_server ? GRPC_CQ_NON_POLLING : GRPC_CQ_DEFAULT_POLLING;
// Create completion queues to listen to incoming rpc requests
for (int i = 0; i < sync_server_settings_.num_cqs; i++) {
sync_server_cqs->emplace_back(
new ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr));
}
}/<code>
- 创建了ServerCompletionQueue(简写为scq)类型的vector sync_server_cqs,并初始化了具体类型的scq
- scq是同步server中非常重要的角色。ServerCompletionQueue可以有多个,它们用来监听外界的请求。还记得第一章中的网络模型,同一个listenfd被分配到了多个epoll中么?那些epoll就在ServerCompletionQueue中。
- 创建了default-executor和resolver-executor线程,等待任务到来
1.2 创建Server
<code> std::unique_ptr<server> server(new Server(
max_receive_message_size_, &args, sync_server_cqs,
sync_server_settings_.min_pollers, sync_server_settings_.max_pollers,
sync_server_settings_.cq_timeout_msec, resource_quota_,
std::move(interceptor_creators_)));/<server>/<code>
Server的构造函数中干了两件事儿:
- 根据sync_server_cqs中的scq个数创建了数目等同的SyncRequestThreadManager(第二章中出现过这个名字),并将scq的指针放到了其中,后面有大用处
- 创建了grpc_server* server_,它才是Server中真正干活的人
1.3 将sync_server_cqs指针放到server_中
<code> for (auto it = cqs_.begin(); it != cqs_.end(); ++it) {
grpc_server_register_completion_queue(server->server_, (*it)->cq(),
nullptr);
}/<code>
确切的说,是将sync_server_cqs中的每个scq中的cq_变量放到_server中的grpc_completion_queue** cqs数组中
1.4 注册具体service
<code> for (auto service = services_.begin(); service != services_.end();
service++) {
if (!server->RegisterService((*service)->host.get(), (*service)->service)) {
return nullptr;
}
}/<code>
这块代码在第二章线程模型的DoWork中会被用到
1.5 bind和listen
<code> bool added_port = false;
for (auto port = ports_.begin(); port != ports_.end(); port++) {
int r = server->AddListeningPort(port->addr, port->creds.get());
if (!r) {
if (added_port) server->Shutdown();
return nullptr;
}
added_port = true;
if (port->selected_port != nullptr) {
*port->selected_port = r;
}
}/<code>
AddListeningPort方法的实际入口在InsecureServerCredentialsImpl类中,执行了bind和listen操作
1.6 server->Start
<code> auto cqs_data = cqs_.empty() ? nullptr : &cqs_[0];
server->Start(cqs_data, cqs_.size());/<code>
- 将start_listener任务放到default-executor线程中,创建epoll,注册listen描述符,注册accept描述符
- 启动SyncRequestThreadManager线程,进入epoll_wait等待,响应读写事件
- 在SyncRequestThreadManager中处理1.4节中注册的service业务逻辑
閱讀更多 路小飯 的文章
關鍵字: service ServerCompletionQueue port