从这个函数可以看出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节都用来介绍这个东西。