WebSocket Protocol Stack in chrome/net
目的
我们想提出在chrome / net中添加WebSocket网络堆栈以实现以下两个目标:
- 在代理解析,代理身份验证,建立SSL连接和HTTP事务等领域,删除SocketStream和其他net /代码的重复代码。
- 准备通过SPDY实现WebSocket多重扩展和WebSocket。
本文档重点介绍chrome / net下的类的设计。
背景
当前设计
当前,WebSocket协议栈基本上位于WebCore的WebSocketChannel中。 它解析传入的字节流并构建要发送的WebSocket帧。
它使用一个名为SocketStreamHandle的接口,该接口提供类似于套接字的功能。 每个WebKit端口都负责使用该端口的网络功能(例如chrome / net,CFNetwork或QTcpSocket)实现该接口。
在Chromium中,SocketStream是实现此功能的实际类,包括代理解析,代理身份验证和SSL连接。
这是当前设计的简化图
问题
当前设计中存在一些突出的问题:
- chrome / net的HTTP堆栈中已经存在SocketStream重新实现功能,例如:代理解析,代理身份验证和SSL连接。
- 当前,WebCore中存在WebSocket协议栈。 但是,这将在我们实现WebSocket复用扩展时出现问题,因为它要求在浏览器进程中而不是在渲染器中存在完整的WebSocket协议堆栈,以便对来自不同选项卡的WebSocket通道进行复用。
- 正在通过SPDY实现WebSocket,这使SocketStream变得更加复杂。
- 人们不了解SocketStream和StreamSocket之间的区别;)
为了解决这些问题,我们建议在chrome / net中引入WebSocket协议栈。 新设计应与其他chrome / net片段保持一致,并应为通过SPDY实现WebSocket复用扩展和WebSocket提供良好的前景。
设计挑战
外发邮件的流量控制
当用户脚本一次发送大消息时,将有大量数据等待临时发送。 由于我们不想在浏览器进程中保存任意大数据,因此必须将它们存储在渲染器中的某个位置,并且浏览器进程应该能够在渲染器的发送缓冲区中有一些空位时通知渲染器。
在原始设计中,传出数据以以下方式处理:
- SocketStreamHandle具有100MiB缓冲区,所有传出数据都在此处进行缓冲,直到浏览器进程中的套接字可写为止。
- SocketStream拥有32KiB缓冲区。 清除缓冲区后,它将发送“ OnSentData”回调,以告知渲染器它可以通过IPC发送更多字节。
现在,我们希望渲染器和浏览器之间基于消息的通信(而不是基于字节流的通信),因此我们需要重新考虑控制传出消息的方式。
IPC频率
我们可能不希望每次接收或发送消息时都调用IPC,因为WebSocket应用程序或服务器可能一次发送许多小消息,并且我们不希望由它们引起的IPC泛滥。
以前避免了此问题,因为在字节流中串联了多个消息。
拟议设计
高层概述![在这里插入图片描述](https://img-blog.csdnimg.cn/2020120815314961.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjIyNjEzNA==,size_16,color_FFFFFF,t_70)
注意:此图中的类名是临时的; 可能需要对其进行修改(欢迎提出建议)。
脚本已发送的WebSocket消息通过content :: WebSocketChannelDispatcher在模块和IPC之间通过函数调用传递到net :: WebSocketChannel。 给定一条消息,WebSokcetChannel将构建一个WebSocket框架,并将其传递给WebSocketStream。 WebSocketStream知道如何将该帧发送到网络,该帧通常是正常的TCP连接,但可能是SPDY流。
当WebSocket消息从网络到达时,它遵循相反的路径。
在本节的其余部分,我们将描述每个网络/组件的详细设计。
套接字层和连接管理
套接字池
我们不想让WebSocket活动连接阻塞或干扰其他HTTP连接,因此需要准备一组用于WebSocket连接的新套接字池。
不确定当前的连接限制集(每个池,每个组和每个代理服务器的最大套接字数)是否可以与WebSockets一起使用。 现在,我想以最低功能开始:将另一个ClientSocketPoolManagerImpl添加到仅管理WebSocket连接的HttpNetworkSession中。 以后,将需要进行更多的研究来确定合适的连接限制数量,或寻求其他连接限制指标的可能性。
我们将向HttpNetworkSession添加另一组套接字池:
class HttpNetworkSession {
public:
…
TransportClientSocketPool* GetTransportSocketPoolForWebSocket();
SSLClientSocketPool* GetSSLSocketPoolForWebSocket();
// … and other pools as well.
…
private:
…
scoped_ptr<ClientSocketPoolManager> socket_pool_manager_;
scoped_ptr<ClientSocketPoolManager> socket_pool_manager_for_websocket_;
…
};
client_socket_pool_manager中的一个新函数。{h,cc}:
int InitSocketHandleForWebSocketRequest(const GURL& request_url, ...);
如果request_url是WebSocket URL