精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

我們聊一下Node.js Inspector源碼解析

開發 前端
之前的文章分析了Node.js Inspector的使用和原理,并粗略地分析了其源碼,因為Node.js Inspector的實現非常復雜,邏輯又非常繞,所以本文打算更深入、更通俗地講解Node.js Inspector的實現。

[[415983]]

之前的文章分析了Node.js Inspector的使用和原理,并粗略地分析了其源碼,因為Node.js Inspector的實現非常復雜,邏輯又非常繞,所以本文打算更深入、更通俗地講解Node.js Inspector的實現。

當我們以以下方式執行我們的應用時

  1. node inspect app.js 

1 初始化

Node.js在啟動的過程中,就會初始化Inspector相關的邏輯。

  1. inspector_agent_ = std::make_unique<inspector::Agent>(this); 

Agent是負責和V8 Inspector通信的對象。創建完后接著執行env->InitializeInspector({})啟動Agent。

  1. inspector_agent_->Start(...); 

Start繼續執行Agent::StartIoThread。

  1. bool Agent::StartIoThread() { 
  2.   io_ = InspectorIo::Start(client_->getThreadHandle(), ...); 
  3.   return true

StartIoThread中的client_->getThreadHandle()是重要的邏輯,我們先來分析該函數。

  1. std::shared_ptr<MainThreadHandle> getThreadHandle() { 
  2.     if (!interface_) { 
  3.       interface_ = std::make_shared<MainThreadInterface>(env_->inspector_agent(), ...); 
  4.     } 
  5.     return interface_->GetHandle(); 

getThreadHandle首先創建來一個MainThreadInterface對象,接著又調用了他的GetHandle方法,我們看一下該方法的邏輯。

  1. std::shared_ptr<MainThreadHandle> MainThreadInterface::GetHandle() { 
  2.   if (handle_ == nullptr) 
  3.     handle_ = std::make_shared<MainThreadHandle>(this); 
  4.   return handle_; 

GetHandlei了創建了一個MainThreadHandle對象,最終結構如下所示。

分析完后我們繼續看Agent::StartIoThread中InspectorIo::Start的邏輯。

  1. std::unique_ptr<InspectorIo> InspectorIo::Start(std::shared_ptr<MainThreadHandle> main_thread, ...) { 
  2.   auto io = std::unique_ptr<InspectorIo>(new InspectorIo(main_thread, ...)); 
  3.   return io; 

InspectorIo::Star里新建了一個InspectorIo對象,我們看看InspectorIo構造函數的邏輯。

  1. InspectorIo::InspectorIo(std::shared_ptr<MainThreadHandle> main_thread, ...) 
  2.     :  
  3.     // 初始化main_thread_ 
  4.     main_thread_(main_thread)) { 
  5.   // 新建一個子線程,子線程中執行InspectorIo::ThreadMain 
  6.   uv_thread_create(&thread_, InspectorIo::ThreadMain, this); 

這時候結構如下。

Inspector在子線程里啟動的原因主要有兩個。

1 如果在主線程里運行,那么當我們斷點調試的時候,Node.js主線程就會被停住,也就無法處理客戶端發過來的調試指令。

2 如果主線程陷入死循環,我們就無法實時抓取進程的profile數據來分析原因。接著繼續看一下子線程里執行InspectorIo::ThreadMain的邏輯。

  1. void InspectorIo::ThreadMain(void* io) { 
  2.   static_cast<InspectorIo*>(io)->ThreadMain(); 
  3.  
  4. void InspectorIo::ThreadMain() { 
  5.   uv_loop_t loop; 
  6.   loop.data = nullptr; 
  7.   // 在子線程開啟一個新的事件循環 
  8.   int err = uv_loop_init(&loop); 
  9.   std::shared_ptr<RequestQueueData> queue(new RequestQueueData(&loop), ...); 
  10.   // 新建一個delegate,用于處理請求 
  11.   std::unique_ptr<InspectorIoDelegate> delegate( 
  12.     new InspectorIoDelegate(queue, main_thread_, ...) 
  13.   ); 
  14.   InspectorSocketServer server(std::move(delegate), ...); 
  15.   server.Start() 
  16.   uv_run(&loop, UV_RUN_DEFAULT); 

ThreadMain里主要三個邏輯

1 創建一個delegate對象,該對象是核心的對象,后面我們會看到有什么作用。

2 創建一個服務器并啟動。

3 開啟事件循環。接下來看一下服務器的邏輯,首先看一下創建服務器的邏輯。

  1. InspectorSocketServer::InspectorSocketServer(std::unique_ptr<SocketServerDelegate> delegate, ...) 
  2.     :  
  3.       // 保存delegate 
  4.       delegate_(std::move(delegate)), 
  5.       // 初始化sessionId 
  6.       next_session_id_(0) { 
  7.   // 設置delegate的server為當前服務器 
  8.   delegate_->AssignServer(this); 

執行完后形成以下結構。

接著我們看啟動服務器的邏輯。

  1. bool InspectorSocketServer::Start() { 
  2.   // DNS解析,比如輸入的是localhost 
  3.   struct addrinfo hints; 
  4.   memset(&hints, 0, sizeof(hints)); 
  5.   hints.ai_flags = AI_NUMERICSERV; 
  6.   hints.ai_socktype = SOCK_STREAM; 
  7.   uv_getaddrinfo_t req; 
  8.   const std::string port_string = std::to_string(port_); 
  9.   uv_getaddrinfo(loop_, &req, nullptr, host_.c_str(), 
  10.                            port_string.c_str(), &hints); 
  11.   // 監聽解析到的ip列表                  
  12.   for (addrinfo* address = req.addrinfo;  
  13.        address != nullptr; 
  14.        address = address->ai_next) { 
  15.  
  16.     auto server_socket = ServerSocketPtr(new ServerSocket(this)); 
  17.     err = server_socket->Listen(address->ai_addr, loop_); 
  18.     if (err == 0) 
  19.       server_sockets_.push_back(std::move(server_socket)); 
  20.  
  21.   } 
  22.  
  23.   return true

首先根據參數做一個DNS解析,然后根據拿到的ip列表(通常是一個),創建對應個數的ServerSocket對象,并執行他的Listen方法。ServerSocket表示一個監聽socket。看一下ServerSocket的構造函數。

  1. ServerSocket(InspectorSocketServer* server) 
  2.             : tcp_socket_(uv_tcp_t()), server_(server) {} 

執行完后結構如下。

接著看一下ServerSocket的Listen方法。

  1. int ServerSocket::Listen(sockaddr* addr, uv_loop_t* loop) { 
  2.   uv_tcp_t* server = &tcp_socket_; 
  3.   uv_tcp_init(loop, server) 
  4.   uv_tcp_bind(server, addr, 0); 
  5.   uv_listen(reinterpret_cast<uv_stream_t*>(server),  
  6.                     511, 
  7.                     ServerSocket::SocketConnectedCallback); 

Listen調用Libuv的接口完成服務器的啟動。至此,Inspector提供的Weboscket服務器啟動了。

2 處理連接

從剛才分析中可以看到,當有連接到來時執行回調ServerSocket::SocketConnectedCallback。

  1. void ServerSocket::SocketConnectedCallback(uv_stream_t* tcp_socket, 
  2.                                            int status) { 
  3.   if (status == 0) { 
  4.     // 根據Libuv handle找到對應的ServerSocket對象 
  5.     ServerSocket* server_socket = ServerSocket::FromTcpSocket(tcp_socket); 
  6.     // Socket對象的server_字段保存了所在的InspectorSocketServer 
  7.     server_socket->server_->Accept(server_socket->port_, tcp_socket); 
  8.   } 

接著看InspectorSocketServer的Accept是如何處理連接的。

  1. void InspectorSocketServer::Accept(int server_port, 
  2.                                    uv_stream_t* server_socket) { 
  3.  
  4.   std::unique_ptr<SocketSession> session( 
  5.       new SocketSession(this, next_session_id_++, server_port) 
  6.   ); 
  7.  
  8.   InspectorSocket::DelegatePointer delegate = 
  9.       InspectorSocket::DelegatePointer( 
  10.           new SocketSession::Delegate(this, session->id()) 
  11.       ); 
  12.  
  13.   InspectorSocket::Pointer inspector = 
  14.       InspectorSocket::Accept(server_socket, std::move(delegate)); 
  15.  
  16.   if (inspector) { 
  17.     session->Own(std::move(inspector)); 
  18.     connected_sessions_[session->id()].second = std::move(session); 
  19.   } 

Accept的首先創建里一個SocketSession和SocketSession::Delegate對象。然后調用InspectorSocket::Accept,從代碼中可以看到InspectorSocket::Accept會返回一個InspectorSocket對象。InspectorSocket是對通信socket的封裝(和客戶端通信的socket,區別于服務器的監聽socket)。然后記錄session對象對應的InspectorSocket對象,同時記錄sessionId和session的映射關系。結構如下圖所示。

接著看一下InspectorSocket::Accept返回InspectorSocket的邏輯。

  1. InspectorSocket::Pointer InspectorSocket::Accept(uv_stream_t* server, 
  2.                                                  DelegatePointer delegate) { 
  3.   auto tcp = TcpHolder::Accept(server, std::move(delegate)); 
  4.   InspectorSocket* inspector = new InspectorSocket(); 
  5.   inspector->SwitchProtocol(new HttpHandler(inspector, std::move(tcp))); 
  6.   return InspectorSocket::Pointer(inspector); 

InspectorSocket::Accept的代碼不多,但是邏輯還是挺多的。

  1. TcpHolder::Pointer TcpHolder::Accept( 
  2.     uv_stream_t* server, 
  3.     InspectorSocket::DelegatePointer delegate) { 
  4.   // 新建一個TcpHolder對象,TcpHolder是對uv_tcp_t和delegate的封裝 
  5.   TcpHolder* result = new TcpHolder(std::move(delegate)); 
  6.   // 拿到TcpHolder對象的uv_tcp_t結構體 
  7.   uv_stream_t* tcp = reinterpret_cast<uv_stream_t*>(&result->tcp_); 
  8.   // 初始化 
  9.   int err = uv_tcp_init(server->loop, &result->tcp_); 
  10.   // 摘取一個TCP連接對應的fd保存到TcpHolder的uv_tcp_t結構體中(即第二個參數的tcp字段) 
  11.   uv_accept(server, tcp); 
  12.   // 注冊等待可讀事件,有數據時執行OnDataReceivedCb回調 
  13.   uv_read_start(tcp, allocate_buffer, OnDataReceivedCb); 
  14.   return TcpHolder::Pointer(result); 

2 新建一個HttpHandler對象。

  1. explicit HttpHandler(InspectorSocket* inspector, TcpHolder::Pointer tcp) 
  2.                      : ProtocolHandler(inspector, std::move(tcp)){ 
  3.  
  4.   llhttp_init(&parser_, HTTP_REQUEST, &parser_settings); 
  5.   llhttp_settings_init(&parser_settings); 
  6.   parser_settings.on_header_field = OnHeaderField; 
  7.   parser_settings.on_header_value = OnHeaderValue; 
  8.   parser_settings.on_message_complete = OnMessageComplete; 
  9.   parser_settings.on_url = OnPath; 
  10.  
  11. ProtocolHandler::ProtocolHandler(InspectorSocket* inspector, 
  12.                                  TcpHolder::Pointer tcp) 
  13.                                  : inspector_(inspector), tcp_(std::move(tcp)) { 
  14.   // 設置TCP數據的handler,TCP是只負責傳輸,數據的解析交給handler處理                                
  15.   tcp_->SetHandler(this); 

HttpHandler是對uv_tcp_t的封裝,主要通過HTTP解析器llhttp對HTTP協議進行解析。

3 調用inspector->SwitchProtocol()切換當前協議為HTTP,建立TCP連接后,首先要經過一個HTTP請求從HTTP協議升級到WebSocket協議,升級成功后就使用Websocket協議進行通信。我們看一下這時候的結構圖。

至此,就完成了連接處理的分析。

3 協議升級

完成了TCP連接的處理后,接下來要完成協議升級,因為Inspector是通過WebSocket協議和客戶端通信的,所以需要通過一個HTTP請求來完成HTTP到WebSocekt協議的升級。從剛才的分析中看當有數據到來時會執行OnDataReceivedCb回調。

  1. void TcpHolder::OnDataReceivedCb(uv_stream_t* tcp, ssize_t nread, 
  2.                                  const uv_buf_t* buf) { 
  3.   TcpHolder* holder = From(tcp); 
  4.   holder->ReclaimUvBuf(buf, nread); 
  5.   // 調用handler的onData,目前handler是HTTP協議 
  6.   holder->handler_->OnData(&holder->buffer); 

TCP層收到數據后交給應用層解析,直接調用上層的OnData回調。

  1. void OnData(std::vector<char>* data) override { 
  2.     // 解析HTTP協議 
  3.     llhttp_execute(&parser_, data->data(), data->size()); 
  4.     // 解析完并且是升級協議的請求則調用delegate的回調OnSocketUpgrade 
  5.     delegate()->OnSocketUpgrade(event.host, event.path, event.ws_key); 

OnData可能會被多次回調,并通過llhttp_execute解析收到的HTTP報文,當發現是一個協議升級的請求后,就調用OnSocketUpgrade回調。delegate是TCP層保存的SocketSession::Delegate對象。來看一下該對象的OnSocketUpgrade方法。

  1. void SocketSession::Delegate::OnSocketUpgrade(const std::string& host, 
  2.                                               const std::string& path, 
  3.                                               const std::string& ws_key) { 
  4.   std::string id = path.empty() ? path : path.substr(1); 
  5.   server_->SessionStarted(session_id_, id, ws_key); 

OnSocketUpgrade又調用來server_(InspectorSocketServer對象)的SessionStarted。

  1. void InspectorSocketServer::SessionStarted(int session_id, 
  2.                                            const std::string& id, 
  3.                                            const std::string& ws_key) { 
  4.   // 找到對應的session對象                                            
  5.   SocketSession* session = Session(session_id); 
  6.   connected_sessions_[session_id].first = id; 
  7.   session->Accept(ws_key); 
  8.   delegate_->StartSession(session_id, id); 

首先通過session_id找到建立TCP連接時分配的SocketSession對象。

1 執行session->Accept(ws_key);回復客戶端同意協議升級。

  1. void Accept(const std::string& ws_key) { 
  2.   ws_socket_->AcceptUpgrade(ws_key); 

從結構圖我們可以看到ws_socket_是一個InspectorSocket對象。

  1. void AcceptUpgrade(const std::string& accept_key) override { 
  2.     char accept_string[ACCEPT_KEY_LENGTH]; 
  3.     generate_accept_string(accept_key, &accept_string); 
  4.     const char accept_ws_prefix[] = "HTTP/1.1 101 Switching Protocols\r\n" 
  5.                                     "Upgrade: websocket\r\n" 
  6.                                     "Connection: Upgrade\r\n" 
  7.                                     "Sec-WebSocket-Accept: "
  8.     const char accept_ws_suffix[] = "\r\n\r\n"
  9.     std::vector<char> reply(accept_ws_prefix, 
  10.                             accept_ws_prefix + sizeof(accept_ws_prefix) - 1); 
  11.     reply.insert(reply.end(), accept_string, 
  12.                  accept_string + sizeof(accept_string)); 
  13.     reply.insert(reply.end(), accept_ws_suffix, 
  14.                  accept_ws_suffix + sizeof(accept_ws_suffix) - 1); 
  15.     // 回復101給客戶端              
  16.     WriteRaw(reply, WriteRequest::Cleanup); 
  17.     // 切換handler為WebSocket handler 
  18.     inspector_->SwitchProtocol(new WsHandler(inspector_, std::move(tcp_))); 

AcceptUpgradeh首先回復客戶端101表示同意升級道WebSocket協議,然后切換數據處理器為WsHandler,即后續的數據按照WebSocket協議處理。

2 執行delegate_->StartSession(session_id, id)建立和V8 Inspector的會話。delegate_是InspectorIoDelegate對象。

  1. void InspectorIoDelegate::StartSession(int session_id, 
  2.                                        const std::string& target_id) { 
  3.   auto session = main_thread_->Connect
  4.       std::unique_ptr<InspectorSessionDelegate>( 
  5.           new IoSessionDelegate(request_queue_->handle(), session_id) 
  6.       ),  
  7.       true); 
  8.   if (session) { 
  9.     sessions_[session_id] = std::move(session); 
  10.     fprintf(stderr, "Debugger attached.\n"); 
  11.   } 

首先通過main_thread_->Connect拿到一個session,并在InspectorIoDelegate中記錄映射關系。結構圖如下。

接下來看一下main_thread_->Connect的邏輯(main_thread_是MainThreadHandle對象)。

  1. std::unique_ptr<InspectorSession> MainThreadHandle::Connect
  2.     std::unique_ptr<InspectorSessionDelegate> delegate, 
  3.     bool prevent_shutdown) { 
  4.  
  5.   return std::unique_ptr<InspectorSession>( 
  6.       new CrossThreadInspectorSession(++next_session_id_, 
  7.                                       shared_from_this(), 
  8.                                       std::move(delegate), 
  9.                                       prevent_shutdown)); 

Connect函數新建了一個CrossThreadInspectorSession對象。

  1. CrossThreadInspectorSession( 
  2.       int id, 
  3.       std::shared_ptr<MainThreadHandle> thread, 
  4.       std::unique_ptr<InspectorSessionDelegate> delegate, 
  5.       bool prevent_shutdown) 
  6.       // 創建一個MainThreadSessionState對象 
  7.       : state_(thread, std::bind(MainThreadSessionState::Create
  8.                                  std::placeholders::_1, 
  9.                                  prevent_shutdown)) { 
  10.     // 執行MainThreadSessionState::Connect                              
  11.     state_.Call(&MainThreadSessionState::Connect, std::move(delegate)); 
  12.   } 

繼續看MainThreadSessionState::Connect。

  1. void Connect(std::unique_ptr<InspectorSessionDelegate> delegate) { 
  2.     Agent* agent = thread_->inspector_agent(); 
  3.     session_ = agent->Connect(std::move(delegate), prevent_shutdown_); 

繼續調agent->Connect。

  1. std::unique_ptr<InspectorSession> Agent::Connect
  2.     std::unique_ptr<InspectorSessionDelegate> delegate, 
  3.     bool prevent_shutdown) { 
  4.  
  5.   int session_id = client_->connectFrontend(std::move(delegate), 
  6.                                             prevent_shutdown); 
  7.   return std::unique_ptr<InspectorSession>( 
  8.       new SameThreadInspectorSession(session_id, client_)); 

繼續調connectFrontend

  1. int connectFrontend(std::unique_ptr<InspectorSessionDelegate> delegate, 
  2.                       bool prevent_shutdown) { 
  3.     int session_id = next_session_id_++; 
  4.     channels_[session_id] = std::make_unique<ChannelImpl>(env_, 
  5.                                                           client_, 
  6.                                                           getWorkerManager(), 
  7.                                                           std::move(delegate), 
  8.                                                           getThreadHandle(), 
  9.                                                           prevent_shutdown); 
  10.     return session_id; 

connectFrontend創建了一個ChannelImpl并且在channels_中保存了映射關系。看看ChannelImpl的構造函數。

  1. explicit ChannelImpl(Environment* env, 
  2.                      const std::unique_ptr<V8Inspector>& inspector, 
  3.                      std::unique_ptr<InspectorSessionDelegate> delegate, ...) 
  4.       : delegate_(std::move(delegate)) { 
  5.  
  6.     session_ = inspector->connect(CONTEXT_GROUP_ID, this, StringView()); 

ChannelImpl調用inspector->connect建立了一個和V8 Inspector的會話。結構圖大致如下。

4 客戶端到V8 Inspector的數據處理

TCP連接建立了,協議升級也完成了,接下來就可以開始處理業務數據。從前面的分析中我們已經知道數據到來時會執行TcpHoldler的handler_->OnData回調。因為已經完成了協議升級,所以這時候的handler變成了WeSocket handler。

  1. void OnData(std::vector<char>* data) override { 
  2.     // 1. Parse. 
  3.     int processed = 0; 
  4.     do { 
  5.       processed = ParseWsFrames(*data); 
  6.       // 2. Fix the data size & length 
  7.       if (processed > 0) { 
  8.         remove_from_beginning(data, processed); 
  9.       } 
  10.     } while (processed > 0 && !data->empty()); 

OnData通過ParseWsFrames解析WebSocket協議。

  1. int ParseWsFrames(const std::vector<char>& buffer) { 
  2.     int bytes_consumed = 0; 
  3.     std::vector<charoutput
  4.     bool compressed = false
  5.     // 解析WebSocket協議 
  6.     ws_decode_result r =  decode_frame_hybi17(buffer, 
  7.                                               true /* client_frame */, 
  8.                                               &bytes_consumed, &output
  9.                                               &compressed); 
  10.     // 執行delegate的回調                                         
  11.     delegate()->OnWsFrame(output); 
  12.     return bytes_consumed; 

前面已經分析過delegate是TcpHoldler的delegate,即SocketSession::Delegate對象。

  1. void SocketSession::Delegate::OnWsFrame(const std::vector<char>& data) { 
  2.   server_->MessageReceived(session_id_, 
  3.                            std::string(data.data(),  
  4.                            data.size())); 

繼續回調server_->MessageReceived。從結構圖可以看到server_是InspectorSocketServer對象。

  1. void MessageReceived(int session_id, const std::string& message) { 
  2.   delegate_->MessageReceived(session_id, message); 

繼續回調delegate_->MessageReceived。InspectorSocketServer的delegate_是InspectorIoDelegate對象。

  1. void InspectorIoDelegate::MessageReceived(int session_id, 
  2.                                           const std::string& message) { 
  3.   auto session = sessions_.find(session_id); 
  4.   if (session != sessions_.end()) 
  5.     session->second->Dispatch(Utf8ToStringView(message)->string()); 

首先通過session_id找到對應的session。session是一個CrossThreadInspectorSession對象。看看他的Dispatch方法。

  1. void Dispatch(const StringView& message) override { 
  2.     state_.Call(&MainThreadSessionState::Dispatch, 
  3.                 StringBuffer::create(message)); 

執行MainThreadSessionState::Dispatch。

  1. void Dispatch(std::unique_ptr<StringBuffer> message) { 
  2.   session_->Dispatch(message->string()); 

session_是SameThreadInspectorSession對象。

  1. void SameThreadInspectorSession::Dispatch( 
  2.     const v8_inspector::StringView& message) { 
  3.   auto client = client_.lock(); 
  4.   if (client) 
  5.     client->dispatchMessageFromFrontend(session_id_, message); 

繼續調client->dispatchMessageFromFrontend。

  1. void dispatchMessageFromFrontend(int session_id, const StringView& message) { 
  2.    channels_[session_id]->dispatchProtocolMessage(message); 

通過session_id找到對應的ChannelImpl,繼續調ChannelImpl的dispatchProtocolMessage。

  1. voiddispatchProtocolMessage(const StringView& message) { 
  2.    session_->dispatchProtocolMessage(message); 

最終調用和V8 Inspector的會話對象把數據發送給V8。至此客戶端到V8 Inspector的通信過程就完成了。

5 V8 Inspector到客戶端的數據處理

接著看從V8 inspector到客戶端的數據傳遞邏輯。V8 inspector是通過channel的sendResponse函數傳遞給客戶端的。

  1. void sendResponse( 
  2.       int callId, 
  3.       std::unique_ptr<v8_inspector::StringBuffer> message) override { 
  4.  
  5.     sendMessageToFrontend(message->string()); 
  6.   } 
  7.  
  8.  void sendMessageToFrontend(const StringView& message) { 
  9.     delegate_->SendMessageToFrontend(message); 
  10.  } 

delegate_是IoSessionDelegate對象。

  1. void SendMessageToFrontend(const v8_inspector::StringView& message) override { 
  2.     request_queue_->Post(id_, TransportAction::kSendMessage, 
  3.                          StringBuffer::create(message)); 
  4.   } 

request_queue_是RequestQueueData對象。

  1. void Post(int session_id, 
  2.             TransportAction action
  3.             std::unique_ptr<StringBuffer> message) { 
  4.  
  5.     Mutex::ScopedLock scoped_lock(state_lock_); 
  6.     bool notify = messages_.empty(); 
  7.     messages_.emplace_back(action, session_id, std::move(message)); 
  8.     if (notify) { 
  9.       CHECK_EQ(0, uv_async_send(&async_)); 
  10.       incoming_message_cond_.Broadcast(scoped_lock); 
  11.     } 
  12.   } 

Post首先把消息入隊,然后通過異步的方式通知async_接著看async_的處理函數(在子線程的事件循環里執行)。

  1. uv_async_init(loop, &async_, [](uv_async_t* async) { 
  2.    // 拿到async對應的上下文 
  3.    RequestQueueData* wrapper = node::ContainerOf(&RequestQueueData::async_, async); 
  4.    // 執行RequestQueueData的DoDispatch 
  5.    wrapper->DoDispatch();});void DoDispatch() { 
  6.     for (const auto& request : GetMessages()) { 
  7.       request.Dispatch(server_); 
  8.     } 
  9.   } 

request是RequestToServer對象。

  1. void Dispatch(InspectorSocketServer* server) const { 
  2.     switch (action_) { 
  3.       case TransportAction::kSendMessage: 
  4.         server->Send( 
  5.             session_id_, 
  6.             protocol::StringUtil::StringViewToUtf8(message_->string())); 
  7.         break; 
  8.     } 
  9.   } 

接著看InspectorSocketServer的Send。

  1. void InspectorSocketServer::Send(int session_id, const std::string& message) { 
  2.   SocketSession* session = Session(session_id); 
  3.   if (session != nullptr) { 
  4.     session->Send(message); 
  5.   } 

session代表可客戶端的一個連接。

  1. void SocketSession::Send(const std::string& message) { 
  2.   ws_socket_->Write(message.data(), message.length()); 

接著調用WebSocket handler的Write。

  1. void Write(const std::vector<char> data) override { 
  2.     std::vector<charoutput = encode_frame_hybi17(data); 
  3.     WriteRaw(output, WriteRequest::Cleanup); 
  4.   } 

WriteRaw是基類ProtocolHandler實現的。

  1. int ProtocolHandler::WriteRaw(const std::vector<char>& buffer, 
  2.                               uv_write_cb write_cb) { 
  3.   return tcp_->WriteRaw(buffer, write_cb); 

最終是通過TCP連接返回給客戶端。

  1. int TcpHolder::WriteRaw(const std::vector<char>& buffer, uv_write_cb write_cb) { 
  2.   // Freed in write_request_cleanup 
  3.   WriteRequest* wr = new WriteRequest(handler_, buffer); 
  4.   uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(&tcp_); 
  5.   int err = uv_write(&wr->req, stream, &wr->buf, 1, write_cb); 
  6.   if (err < 0) 
  7.     delete wr; 
  8.   return err < 0; 

新建一個寫請求,socket可寫的時候發送數據給客戶端。

 

后記:Node.js Inspector的原理雖然不復雜的,但是實現實在太繞了。

 

責任編輯:武曉燕 來源: 編程雜技
相關推薦

2021-08-05 05:46:06

Node.jsInspector工具

2023-06-20 06:44:14

Node.jsCPU 負載

2022-03-13 08:48:12

inspectorNode.js開發

2021-04-21 14:19:52

javaignalHandle接口

2019-12-17 11:40:44

Node.js模塊前端

2025-01-10 11:07:28

2021-10-12 23:45:43

NodeJs事件

2014-04-01 11:02:00

Node.jsWeb Socket聊天程序

2012-05-30 09:12:46

NodeJSRubyRails

2013-11-01 09:34:56

Node.js技術

2015-03-10 10:59:18

Node.js開發指南基礎介紹

2022-10-18 18:43:40

Node.js低代碼

2011-09-08 14:07:28

Node.js

2021-04-27 07:52:18

SQLNULLOR

2021-10-23 06:42:46

Node.js 抓取堆快照.js

2011-09-02 14:47:48

Node

2011-11-01 10:30:36

Node.js

2011-09-08 13:46:14

node.js

2011-09-09 14:23:13

Node.js

2012-10-24 14:56:30

IBMdw
點贊
收藏

51CTO技術棧公眾號

亚洲一区三区视频在线观看| 日韩不卡高清视频| 91超碰caoporn97人人| 日韩激情一二三区| 隣の若妻さん波多野结衣| 热re99久久精品国99热蜜月| 夜夜嗨av一区二区三区中文字幕| 日本免费一区二区三区四区| 97人妻精品一区二区三区免费| 中文字幕9999| 久久人人超碰| 日本免费一区视频| 精品一区二区三区无码视频| 欧美日韩在线不卡| 少妇精品久久久| 色婷婷在线观看视频| 国产中文字幕日韩| 成人动漫一区二区三区| 成人亚洲性情网站www在线观看| 韩日视频在线观看| 欧美一区二区视频在线观看 | 国产精品久久久久久免费播放| 久热这里只精品99re8久 | 亚洲欧美日韩激情| 成人免费视频在线观看超级碰| 91一区一区三区| 久久av色综合| 中国免费黄色片| 欧美国产日本高清在线| 国产精品一区二区黑丝| 哥也色在线视频| 人人爽人人爽av| 久久最新资源网| 狠狠色狠狠色综合| 直接在线观看的三级网址| www.国产福利| 欧美高清视频在线观看| 国产乱子伦视频一区二区三区| 成人在线观看免费| 中文字幕在线视频一区二区三区| 久久国产精品影视| 成人激情黄色小说| 电影一区二区三| 高潮毛片无遮挡| 国产日韩欧美日韩| 亚洲成人自拍网| 国产一区二区三区不卡视频网站| 亚洲无码久久久久久久| 国产精品视频一二三四区| 日韩午夜小视频| 日韩不卡一区二区三区| 大桥未久在线播放| 三级影片在线观看| 三区精品视频观看| 亚洲精品国产suv| 国产高清精品在线| 91亚洲精品在看在线观看高清| av中文在线播放| 日日噜噜噜噜夜夜爽亚洲精品| 欧美成va人片在线观看| 九九热在线视频观看这里只有精品| 日韩毛片免费观看| 欧美亚韩一区二区三区| 精品人妻人人做人人爽| 欧美精品一本久久男人的天堂| 国产亚洲一区二区三区在线观看| 红杏视频成人| 五月婷婷激情在线| 一级黄色免费视频| 国产精品久久久久久久久久直播| 日韩美女一区二区三区| 国内外成人在线| 亚洲高清在线一区| 丰满人妻一区二区| 好吊操视频这里只有精品| 成人羞羞视频免费| 亚洲黄色在线看| 91免费版在线看| 久久精品国产www456c0m| 思思99re6国产在线播放| 亚洲波多野结衣| 免费在线观看视频a| 欧美一级黄色网| 欧美日韩精品一区二区三区蜜桃 | 精品久久久网| www.色婷婷.com| 波多野结衣加勒比| 一区二区三区免费看| 精品国产网站地址| 亚洲一区二区三区不卡国产欧美| 一本色道久久综合| 日韩有码欧美| 色哟哟在线观看| 日本精品人妻无码77777| 国产毛片视频网站| 国产精品自拍网| 日韩精品福利网站| 亚洲日本在线看| 亚洲激情不卡| 欧美日本三级| 麻豆传媒在线完整视频| www.毛片.com| 无码国产精品久久一区免费| 伊人久久青草| 日本高清视频精品| 亚洲国产97在线精品一区| 亚洲同性同志一二三专区| 国产精品视区| 日本福利一区| av资源新版天堂在线| 国产草草影院ccyycom| 自拍偷拍视频亚洲| 久久婷婷国产精品| 精品国产免费一区二区三区 | 瑟瑟在线观看| 欧美激情一区二区视频| 99热成人精品热久久66| 91视频8mav| 欧美久久久精品| 7777女厕盗摄久久久| 国产精品久久久久久久浪潮网站| 亚洲麻豆视频| 同性恋视频一区| 爱情岛论坛亚洲品质自拍视频网站| 亚洲av无码乱码国产精品久久 | www.亚洲激情.com| 在线欧美亚洲| 欧美交a欧美精品喷水| 亚洲精品一区| 成人动漫在线免费观看| 国产精品怡红院| 精品无码免费视频| 中文字幕在线免费看线人| 午夜视频在线瓜伦| 美女黄色片网站| 免费一区二区三区| 国产免费一区二区三区在线能观看| 日韩最新中文字幕电影免费看| 91麻豆精品91久久久久久清纯| 亚洲影视在线观看| 亚洲国产成人私人影院tom| 国内欧美视频一区二区| 国产视频一区免费看| 日韩一级毛片| 蜜桃一区av| 玖玖精品在线| 自拍视频在线看| 日本亚洲精品| 国产suv一区二区| aaa在线视频| 中文字幕手机在线观看| 久久美女免费视频| 北京富婆泄欲对白| 亚洲一二区在线观看| www..com日韩| 亚洲最新免费视频| 日本一区二区高清视频| 国产欧美一区二区视频| 999久久久| 91最新在线免费观看| 国产日韩专区在线| 国产精品免费小视频| 国产精品入口尤物| 国模吧一区二区| 久久久999国产精品| 爽爽爽爽爽爽爽成人免费观看| 这里只有精品在线观看| 中文字幕欧美日韩精品| www.xxxx欧美| 久久综合国产精品台湾中文娱乐网| 中国china体内裑精亚洲片| 国产午夜精品全部视频在线播放| 亚洲理论在线a中文字幕| 亚洲欧美制服中文字幕| 精品亚洲一区二区三区在线观看| 亚洲国产成人精品电影| 亚洲男人的天堂在线| 在线成人激情黄色| 久久综合久中文字幕青草| 欧美日韩成人在线播放| 久久久久国产视频| 欧美一区第一页| 国产精品免费一区| 国产高清精品一区二区三区| 欧美日韩三区四区| 国产精品夜夜夜爽张柏芝| 国产精品视频网站在线观看 | 国产精品久久久国产盗摄| 999久久久久| 五月婷婷激情在线| 米奇777四色精品人人爽| 黄色小说在线播放| 欧美www.| 风间由美中文字幕在线看视频国产欧美 | 狠狠噜噜久久| 蜜臂av日日欢夜夜爽一区| 国产精品一二二区| 国产视频一区二区在线| 亚洲成人手机在线| 欧美一区二区在线免费观看| 亚洲国产欧美一区二区丝袜黑人| 日韩专区在线观看| 欧美精品做受xxx性少妇| 国产精品wwww| 日本中文不卡| 黄色免费观看视频网站| 好男人香蕉影院| 青青操在线视频观看| 在线观看免费高清视频| 国产51人人成人人人人爽色哟哟| 超碰电影在线播放| 日韩精品一级| 婷婷亚洲综合| 黄页网站大全一区二区| 一区二区视频免费在线观看| 日韩视频免费观看高清完整版在线观看 | 青青热久免费精品视频在线18| 免费av一区| 激情综合色播五月| 一区二区免费在线| 精品视频在线播放免| 国产精国产精品| 亚洲资源在线网| 午夜影院福利社| 国产一级淫片a视频免费观看| 尤物网在线观看| 97精品久久| 蜜臀av亚洲一区中文字幕| 亚洲自拍偷拍麻豆| 亚洲午夜女主播在线直播| 国产在线播放91| 干日本少妇首页| 免费在线观看国产精品| 国产三级在线观看| 动漫3d精品一区二区三区乱码| 秋霞电影一区二区| 欧美日韩激情小视频| 久久亚洲成人精品| 色噜噜狠狠色综合网| 黄色网址在线视频| 超碰在线观看av| 大胆国模一区二区三区| 日本欧美一区二区三区乱码| 黄色91在线观看| 久久久久久久久国产| 欧洲成人性视频| 久久久国产91| 亚洲aⅴ男人的天堂在线观看| av电影一区二区三区| 精品日韩在线视频| 亚洲 欧美 激情 小说 另类| 天堂av一区| 成人久久视频在线观看| 欧美成人激情免费网| 99久久精品无码一区二区毛片 | 日本一区二区三区视频免费看| 精品少妇一区二区三区免费观| 俄罗斯嫩小性bbwbbw| 日韩精品成人| 91亚洲大成网污www| 国产小视频国产精品| 偷拍视频一区二区| 成人午夜免费影院| 亚洲精品白浆| 久久国产精品毛片| 欧美午夜一区二区三区| 国产精品亚洲美女av网站| 永久免费的av网站| 亚洲精品一区二区三区四区 | 日本精品一区二区三区高清| 国产精品99久久久久久久久久久久| 少妇激情一区二区三区| 国产亲伦免费视频播放| 全国精品免费看| 亚洲欧洲性图库| 国内精品久久久久影院 日本资源| 日韩网址在线观看| 97caocao| 香蕉久久精品| 一区二区三区四区精品在线视频 | 欧美在线观看视频一区| 一区二区三区影院| 国产精品福利久久久| 无码人妻一区二区三区一| 蜜桃成人在线视频| 在线亚洲成人| 精品播放一区二区| 中文字幕一区二区三区有限公司| 国内精品福利视频| 欧美日韩黄网站| 日韩一区在线看| 国产精品第1页| aaaaa级少妇高潮大片免费看| 秋霞在线午夜| 国产黄色精品视频| 久久这里有精品| 亚洲欧美一区二区三区不卡| 在线观看美女网站大全免费| 日韩av二区在线播放| 亚洲免费福利视频| 国产真实乱子伦| 国产资源在线观看| 日日嗨av一区二区三区四区| 亚洲乱码一区av黑人高潮| 少妇无码av无码专区在线观看| 91国产精品一区| 天天综合一区| 91精品国产一区二区三区香蕉| 熟女熟妇伦久久影院毛片一区二区| 亚洲在线免费观看视频| 国产精品久久久久9999赢消| 欧美一区二区三区视频在线观看| 久久最新免费视频| 欧美一级特黄aaaaaa| 国产精品五区| 日韩中文字幕国产| 久久无码专区国产精品s| 久久影院午夜精品| 中文无字幕一区二区三区| 国产精品一区二区3区| 亚洲精品卡一卡二| 日本中文字幕在线一区| 色婷婷亚洲综合| 欧美与动交zoz0z| 午夜视频福利在线观看| 精品中文字幕一区二区小辣椒| 欧美成年人网站| 亚洲精品视频网址| 6080成人| 3d成人h动漫网站入口| 免费av手机在线观看| sese一区| 久久青草欧美一区二区三区| 91久久国产自产拍夜夜嗨| 国产视频1区2区| 欧美午夜电影在线观看| 色久欧美在线视频观看| 超碰97在线资源站| 88久久精品| 91精品国产91久久久久久最新毛片| 日本三级免费观看| 91在线超碰| 一区二区在线看| 国产传媒久久久| 黄网站视频在线观看| 中文字幕欧美一| 香蕉久久夜色| 美女羞羞视频在线观看| 国产精品视频看| 日本黑人久久| 中文字幕在线播放| 中文字幕巨乱亚洲| 一道精品一区二区三区| h视频网站在线观看| 国产欧美久久久精品影院| 欧美日韩无遮挡| 91欧美在线视频| 国产精品视频一区二区三区不卡| 色综合电影网| 国产一二区在线观看| 亚洲欧美视频在线观看视频| 97久久国产亚洲精品超碰热| 性欧美videos高清hd4k| 欧美色播在线播放| 可以在线看的黄色网址| 国产69精品久久久久9999人| 欧美日韩一区成人| 日韩精品xxx| 欧美大胆视频| 中文字幕无线精品亚洲乱码一区| 青青青手机在线视频| 亚洲五月婷婷| 日韩av理论片| 精品人妻无码一区二区三区蜜桃一| 国产不卡视频一区二区三区| 欧美韩国日本精品一区二区三区| av色图一区| 欧美视频二区36p| 99九九99九九九99九他书对| 日韩啪啪网站| 久久深夜福利免费观看| 久久高清免费视频| 日韩av午夜在线观看| 久久er99热精品一区二区三区| 69久久精品| 欧洲生活片亚洲生活在线观看| 亚洲精品一二三四| 色综合狠狠操| 国产精品福利观看| 婷婷在线免费观看| 一区二区三区精品久久久| 波多野结衣综合网| 成人在线分类| 久久伊人色综合| 涩涩视频在线观看| 日本一区二区成人在线| 免费在线激情视频| 中文字幕中文字幕精品| 68精品国产免费久久久久久婷婷| 精品人妻一区二区三区浪潮在线 |