谷歌浏览器的源码分析(30)

系统 1741 0
 

上次说到函数 WinHttpReadData 接收数据到缓冲区里,那么这些数据又是怎么样传送给下一步处理的呢?带着这个问题,我们来分析下面这段代码,如下:

#001   void HttpTransactionWinHttp::HandleStatusCallback(DWORD status,

#002                                                     DWORD_PTR result,

#003                                                      DWORD error,

#004                                                     DWORD secure_failure) {

#005     int rv = ERR_FAILED;

#006  

#007     switch (status) {

#008       case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:

#009         rv = DidReceiveError(error, secure_failure);

#010         break;

......

#027  

#028     if (rv == ERR_IO_PENDING) {

#029       session_callback_->AddRef();   // balanced when callback runs.

#030     } else if (callback_) {

#031       DoCallback(rv);

#032     }

#033   }

 

通过上面的函数可以看到,当数据接收完成后,就会调用 DoCallback 函数处理接收到的数据。 DoCallback 函数的代码如下:

 

#001   void HttpTransactionWinHttp::DoCallback(int rv) {

#002     DCHECK(rv != ERR_IO_PENDING);

#003     DCHECK(callback_);

#004  

#005     // since Run may result in Read being called, clear callback_ up front.

#006     CompletionCallback* c = callback_;

#007     callback_ = NULL;

# 008     c ->Run(rv);

#009   }

 

看到这里又是一个回调函数 c->Run 的通知,它是调用开始创建这个连接时设置的回调对象。如果是 HTTP 请求,那么这个请求回调函数是对象 URLRequestHttpJob 里的函数,也就是调用 URLRequestHttpJob::OnReadCompleted 函数,这个函数是当数据接收完成,或接收失败,或者接收还没有完成时都会调用。这个函数代码如下:

#001   void URLRequestHttpJob::OnReadCompleted(int result) {

#002     read_in_progress_ = false;

#003  

 

这里是接收数据完成。

#004     if (result == 0) {

#005       NotifyDone(URLRequestStatus());

#006     } else if (result < 0) {

 

这里是接收数据出错划。

#007       NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, result));

#008     } else {

 

这里是接收数据还没有完成。

#009       // Clear the IO_PENDING status

#010       SetStatus(URLRequestStatus());

#011     }

#012  

#013     NotifyReadComplete(result);

#014   }

 

当上面读取数据完成时,就开始把接收到数据通过类 ResourceDispatcherHost 来发送出去,而类 ResourceDispatcherHost 发送数据的方式比较特别,它不是通过消息把整块数据用命名管道发送的,而是通过共享内存的方式让另一个进程来读取数据,这样达到速度快的特点,可见可多米处理处理考虑的都是速度,它的代码如下:

#001   bool OnReadCompleted(int request_id, int* bytes_read) {

#002       if (!*bytes_read)

#003         return true;

#004       DCHECK(read_buffer_.get());

#005  

#006       if (!rdh_->WillSendData(render_process_host_id_, request_id)) {

#007         // We should not send this data now, we have too many pending requests.

#008         return true;

#009       }

#010  

 

这里创建共享内存。

#011       SharedMemoryHandle handle;

#012       if (!read_buffer_->GiveToProcess(render_process_, &handle)) {

#013         // We wrongfully incremented the pending data count. Fake an ACK message

#014         // to fix this. We can't move this call above the WillSendData because

#015         // it's killing our read_buffer_, and we don't want that when we pause

#016         // the request.

#017         rdh_->OnDataReceivedACK(render_process_host_id_, request_id);

#018         return false;

#019       }

#020  

 

把共享内存通过管道消息发送给渲染进程。

#021       receiver_->Send(new ViewMsg_Resource_DataReceived(

#022           routing_id_, request_id, handle, *bytes_read));

#023  

#024       return true;

#025     }

#026  

 

共享内存是使用 Windows API 函数 CreateFileMapping 来创建内存共享文件实现的,具体实现方法请参考类 SharedMemory 的实现。这里既然把消息通过管道发送出去了,那么在另一个线程里肯定就处理的这个消息,下一次再来分析那部份代码。

谷歌浏览器的源码分析(30)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论