转载
How to Write a QUIC Endpoint Program
要编写使用QUIC的应用程序,需要创建一些新类以及继承一些QUIC类。 本文档通过QUIC的 客户端和服务器程序作为示例,介绍如何在自己的应用程序中使用QUIC。
使用的proto-quic版本为:Updating to 56.0.2912.0 (#15)。
1 新类
为了方便处理所有的QUIC类,可能需要创建封装客户端和服务器功能的类。 此外,至少需 要创建实现QuicPacketWriter接口的类。
1.1 QUIC客户端
需要一个类,以创建一个QuicSimpleClient类[src/net/tools/quic_simple_client.h&.cc] ( 其基类是QuicClientBase类[src/net/tools/quic_client_base.h&.cc] 和 QuicChromiumPacketReader::Visitor类[src/net/quic/chromium/quic_chromium_packet_reader.h&cc], QuicClientBase的基类是QuicClientPushPromiseIndex::Delegate和QuicSpdyStream::Visitor), 连接类和数据包写入器,并连接所有这些类。 它还必须读取网络数据包并将它们分派到会话中。
QUIC客户端的二进制文件为quic_client[src/net/tools/quic/quic_simple_client_bin.cc], 在main函数中调用QuicSimpleClient类的基本功能方法。其流程如下图所示。
以下对每一步进行详细介绍:
创建QUIC客户端可以分为下面的几个步骤。 首先,必须确定要连接的IP地址,服务器ID和 要使用的QUIC版本。 服务器ID作为所要连接到的服务器的标识,是由HTTP方案(http或 https),主机和端口组成的。 示例客户端接收构造函数中的这些参数(还包括epoll服务 器)并将它们存储为属性。
QuicSimpleClient::QuicSimpleClient(
IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
std::unique_ptr<ProofVerifier> proof_verifier)
: QuicSimpleClient(server_address,
server_id,
supported_versions,
QuicConfig(),
std::move(proof_verifier)) {}
QuicSimpleClient::QuicSimpleClient(
IPEndPoint server_address,
const QuicServerId& server_id,
const QuicVersionVector& supported_versions,
const QuicConfig& config,
std::unique_ptr<ProofVerifier> proof_verifier)
: QuicClientBase(server_id,
supported_versions,
config,
CreateQuicConnectionHelper(),
CreateQuicAlarmFactory(),
std::move(proof_verifier)),
initialized_(false),
packet_reader_started_(false),
weak_factory_(this) {
set_server_address(server_address);
}
然后初始化客户端以创建连接,应该在调用Connect函数之前。打开UDP套接字,设置接收和 发送缓冲区大小,并在添加QuicChromiumPacketReader类 [src/net/quic/chromium/quic_chromium_packet_reader.h&cc]。
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);
}
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 =