Chrome原始碼分析之socket(二)

來源:互聯網
上載者:User

從這個函數可以看出Chrome採用WSAEventSelect來同伺服器端建立串連,雖然WSAEventSelect的在輸送量和處理多串連的效能這2方面無法與重疊I/O和完成度連接埠相提並論,但是用在用戶端上足矣,而且WSAEventSelect不象WSASyncSelect那樣需要與視窗控制代碼相關聯,還能減小網路部分的耦合度,應該說是個不錯的選擇,不過WSAEventSelect僅僅用於TCP的串連階段,而發送或者接收資料採用了重疊連接埠模型,之所以如此,可能是重疊連接埠只支援Accept,read,write這三個功能,微軟更傾向於把重疊連接埠用於伺服器端,connect則缺乏支援。

接著分析write函數:

 

AssertEventNotSignaled(core_->write_overlapped_.hEvent); 

接著重設事件對象為未通知狀態

 

 

  int rv = WSASend(socket_, &core_->write_buffer_, 1, &num, 0,

                   &core_->write_overlapped_, NULL);

  if (rv == 0) {

    if (ResetEventIfSignaled(core_->write_overlapped_.hEvent)) {

      rv = static_cast<int>(num);

      if (rv > buf_len || rv < 0) {

        LOG(ERROR) << "Detected broken LSP: Asked to write " << buf_len

                   << " bytes, but " << rv << " bytes reported.";

        return ERR_WINSOCK_UNEXPECTED_WRITTEN_BYTES;

      }

      static base::StatsCounter write_bytes("tcp.write_bytes");

      write_bytes.Add(rv);

      if (rv > 0)

        use_history_.set_was_used_to_convey_data();

      LogByteTransfer(net_log_, NetLog::TYPE_SOCKET_BYTES_SENT, rv,

                      core_->write_buffer _.buf);

      return rv;

    }

  } else {

    int os_error = WSAGetLastError();

    if (os_error != WSA_IO_PENDING)

      return MapWinsockError(os_error);

  }

 

 

上面這段首先調用WSASend將資料發送出去,接著進行各種錯誤檢查。然後設定回呼函數:

 

core_->WatchForWrite();

 

  waiting_write_ = true;

  write_callback_ = callback;

  core_->write_iobuffer_ = buf;

 

 

關於回調的設定的全部細節就在WatchForWrite函數中,而該函數只是調用了write_watcher_.StartWatching(write_overlapped_.hEvent, &writer_);

而StartWatching是ObjectWatcher的一個成員函數,我們先分析一下這個ObjectWatcher類,

 

ObjectWatcher的代碼在另外一個獨立的源檔案中,並且被包含在base命名空間中,說明這是一個通用的類。

 

這裡首先需簡要介紹一下Chrome中線程的實現方式。從實現來說,Chrome的執行緒模式與很多現場一樣,用的是訊息迴圈的手段。每個Chrome乾的事情基本上就是在訊息迴圈中等待並執行任務。Chrome又對線程分類,根據線程類別的不同,所起的訊息迴圈有所不同。比如處理進網路I/O的線程用的是MessagePumpForIO類,處理UI的線程用的是MessagePumpForUI類,一般的線程用到的是MessagePumpDefault類。不同的訊息迴圈類,主要差異有兩個,一是訊息迴圈中需要處理什麼樣的訊息和任務,第二個是迴圈流程,比如是死迴圈還是阻塞在某訊號量上。一個完整版的Chrome訊息迴圈,包含處理Windows的訊息,處理各種Task,處理各個訊號量觀察者(Watcher),然後阻塞在某個訊號量上等待喚醒。一般來說線程迴圈在處理Watcher的時候只需要檢查其訊號量,而不需要阻塞在某個I/O上,很好的實現了網路I/O的非同步性。

 

ObjectWatcher即是封裝了與Watcher相關的資料和操作,本身繼承自MessageLoop的成員類DestructionObserver,有2個主要的成員函數,StartWatching開始監視訊號量,StopWatching停止監視訊號量,DoneWaiting是線程池的回呼函數,成員變數主要是watch_,一個Watch結構體。一個私人類Delegate。Watch結構體是ObjectWatcher類的核心,Watch的定義如下:

 

struct ObjectWatcher::Watch : public Task {

  ObjectWatcher* watcher;   

  HANDLE object;             // 被監視的訊號量

  HANDLE wait_object;        // RegisterWaitForSingleObject返回的線程池註冊控制代碼

  MessageLoop* origin_loop;  // 所屬線程的指標

  Delegate* delegate;        // Delegate 指標

  bool did_signal;           // 執行標識

 

  virtual void Run() {

    //被線程執行函數

    if (!watcher)

      return;

 

    DCHECK(did_signal);

    watcher->StopWatching();

 

    delegate->OnObjectSignaled(object);

  }

};

 

 

這裡有必須詳細分一下Chrome的執行緒模式,因此下面2節都用來介紹這個東西。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.