從這個函數可以看出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節都用來介紹這個東西。