GRPC-C++源碼分析(二)--main函數主要流程

如果沒有特殊喜好,推薦從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業務邏輯


分享到:


相關文章: