参考文献
[1] 参考博客一
[2] 参考博客二
[3] QUIC源码学习–该文章比较详细
客户端处理逻辑和实现

1. 单步调试过程中遇到的类
2.1 QuicParseCommandLineFlags
Quic Parse命令行标志类,主要是解析命令行输入的指令
2.2 QuicSimpleClientFactory
一个工厂模式类,作用是基于简单工厂模式创建基于QUIC协议的Client。他的基类的是ClientFactory。ClientFactory没有父类。简单工厂模式的实现可以参考上述博客。
class QuicSimpleClientFactory : public quic::QuicToyClient::ClientFactory
2.3 ClientFactory
该类主要包含一个关键的成员函数
- CreateClient():创建客户端
2.4 QuicToyClient
- 该类中实现了类ClientFactory
- 一个关键成员函数: SendRequestsAndPrintResponses()。作用是发送请求并打印响应
该类中包含一个私有变
- ClientFactory* client_factory_;其就是创建一个生产Client的工厂
2.5 QuicUrl
这是一个包装GURL的实用程序类。不是很明白其作用。
2.6 GetQuicFlags
这应该是一个Quic相关参数的解析函数,但是不是很明白是干什么的。
2.7 ParsedQuicVersionVector
该类主要是获取当前支持的QUIC协议版本,并创建一个vector进行存储。
2.8 ProofVerifier
数字签名认证
2.9 QuicCofing
获取配置文件并初始化一个配置变量。QuicConfig包含在加密握手中协商的非加密配置选项。
QuicConfig在实例时会调用SetDefaults()函数。SetDfaults()函数就是设置一一些初始化的变量。
void QuicConfig::SetDefaults() {
SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
SetMaxBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection);
SetMaxUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection);
max_time_before_crypto_handshake_ =
QuicTime::Delta::FromSeconds(kMaxTimeForCryptoHandshakeSecs);
max_idle_time_before_crypto_handshake_ =
QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs);
max_undecryptable_packets_ = kDefaultMaxUndecryptablePackets;
SetInitialStreamFlowControlWindowToSend(kMinimumFlowControlSendWindow);
SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow);
SetMaxAckDelayToSendMs(kDefaultDelayedAckTimeMs);
SetAckDelayExponentToSend(kDefaultAckDelayExponent);
SetMaxPacketSizeToSend(kMaxIncomingPacketSize);
SetMaxDatagramFrameSizeToSend(kMaxAcceptedDatagramFrameSize);
}
2.10 AddressList
2.11 SynchronousHostResolver
同步解析主机名
2.12 QuicIpAdress
从给定主机名确定要连接的IP地址
2.13 QuicServerId
用于标识会话的id。包括主机名、端口、方案和保密模式。
// QuicServerId的构造函数
QuicServerId::QuicServerId(const std::string& host,
uint16_t port,
bool privacy_mode_enabled)
: host_(host), port_(port), privacy_mode_enabled_(privacy_mode_enabled) {}
2.13 QuicSoketAddress
quic的socket address
3. 重要的函数
3.1 CreateClient函数
该函数是简单工厂类(QuicSimpleClientFactory)中的一个函数,主要是为了创建一个客户端使实体。
3.2 Initialize函数
- QuicClient派生于QuicSpdyClientBase
- QuicSpdyClientBase 派生于 QuicClientBase, QuicClientPushPromiseIndex::Delegate, QuicSpdyStream::Visitor
调用方式:client->Initialize()
这个是QuicClienbase中的一个成员函数,该函数的作用如下:
- 初始化,接收窗口session 15MB, stream 6MB; 并且初始化network_helper_,网络事件机制;
- 在StartConnect 或者 Connect之前调用
// Initialize()函数的实现
bool QuicClientBase::Initialize() {
//......
// If an initial flow control window has not explicitly been set, then use the
// same values that Chrome uses.
const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
//.....
if (!network_helper_->CreateUDPSocketAndBind(server_address_,
bind_to_address_, local_port_)) {
return false;
}
initialized_ = true;
return true;
}
3.3 Connect()函数
bool Connect() :连接quic server,包括同步加密密钥,和handshake。会调用StartConnect()
3.4 StartConnect()函数
void QuicClientBase::StartConnect(); :连接quic server,包括 同步加密密钥,和handshake;
- 创建QuicPacketWriter;
- 创建QuicSession;
- 创建QuicConnection(其最为QuecSession的成员对象);
void QuicClientBase::StartConnect() {
.......
QuicPacketWriter* writer = network_helper_->CreateQuicPacketWriter();//创建writer接口
......
session_ = CreateQuicClientSession(
supported_versions(),
new QuicConnection(GetNextConnectionId(), server_address(), helper(),
alarm_factory(), writer,
/* owns_writer= */ false, Perspective::IS_CLIENT,
can_reconnect_with_different_version
? ParsedQuicVersionVector{mutual_version}
: supported_versions()));
// Reset |writer()| after |session()| so that the old writer outlives the old
// session.
set_writer(writer);
InitializeSession();
set_connected_or_attempting_connect(true);
}
4. 客户端建立连接的过程
(1) 首先基于简单工程模式实例化一个客户端工程后调用SendRequestsAndPrintResponses()函数。
QuicSimpleClientFactory factory;
quic::QuicToyClient client(&factory);
return client.SendRequestsAndPrintResponses(urls);
(2) 创建具体的“客户端产品”
std::unique_ptr<QuicSpdyClientBase> client = client_factory_->CreateClient()
(3) 客户端的初始化
- 设置接受和发送缓冲区大小;
- 基于UDP创建socket并绑定服务端的IP和Port,调用函数CreateUDPSocketAndBind();
- 添加QuicChromiumPacketReader类
bool QuicClientBase::Initialize() {
...
// If an initial flow control window has not explicitly been set, then use the
// same values that Chrome uses.
const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
...
if (!CreateUDPSocketAndBind(server_address_, bind_to_address_, local_port_)) {
return false;
}
initialized_ = true;
return true;
}
bool QuicSimpleClient::CreateUDPSocketAndBind(IPEndPoint server_address,
IPAddress bind_to_address,
int bind_to_port) {
std::unique_ptr<UDPClientSocket> socket(
new UDPClientSocket(DatagramSocket::DEFAULT_BIND, RandIntCallback(),
&net_log_, NetLogSource()));
int address_family = server_address.GetSockAddrFamily();
if (bind_to_address.size() != 0) {
client_address_ = IPEndPoint(bind_to_address, bind_to_port);
} else if (address_family == AF_INET) {
client_address_ = IPEndPoint(IPAddress::IPv4AllZeros(), bind_to_port);
} else {
client_address_ = IPEndPoint(IPAddress::IPv6AllZeros(), bind_to_port);
}
// 基于操作系统提供的UDP套接字连接服务器
int rc = socket->Connect(server_address);
if (rc != OK) {
LOG(ERROR) << "Connect failed: " << ErrorToShortString(rc);
return false;
}
// 设置接受缓冲区大小
rc = socket->SetReceiveBufferSize(kDefaultSocketReceiveBuffer);
if (rc != OK) {
LOG(ERROR) << "SetReceiveBufferSize() failed: " << ErrorToShortString(rc);
return false;
}
// 设置发送缓冲区大小
rc = socket->SetSendBufferSize(kDefaultSocketReceiveBuffer);
if (rc != OK) {
LOG(ERROR) << "SetSendBufferSize() failed: " << ErrorToShortString(rc);
return false;
}
rc = socket->GetLocalAddress(&client_address_);
if (rc != OK) {
LOG(ERROR) << "GetLocalAddress failed: " << ErrorToShortString(rc);
return false;
}
socket_.swap(socket);
// std::unique_ptr<QuicChromiumPacketReader> packet_reader_
packet_reader_.reset(new QuicChromiumPacketReader(</

本文详细解析了QUIC客户端的初始化、连接过程、数据发送与接收,以及服务器端如何处理CHLO和CHLO包。涉及类QuicParseCommandLineFlags、QuicSimpleClientFactory、QuicConfig等核心组件,以及关键函数如CreateClient、Connect和ProcessPacket的实现。
最低0.47元/天 解锁文章
715

被折叠的 条评论
为什么被折叠?



