参考文献
[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(
socket_.get(), &clock_, this, kQuicYieldAfterPacketsRead,
QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
NetLogWithSource()));
if (socket != nullptr) {
socket->Close();
}
return true;
}
class NET_EXPORT_PRIVATE QuicChromiumPacketReader {
public:
class NET_EXPORT_PRIVATE Visitor {
public:
virtual ~Visitor() {}
virtual void OnReadError(int result,
const DatagramClientSocket* socket) = 0;
virtual bool OnPacket(const QuicReceivedPacket& packet,
IPEndPoint local_address,
IPEndPoint peer_address) = 0;
};
QuicChromiumPacketReader(DatagramClientSocket* socket,
QuicClock* clock,
Visitor* visitor,
int yield_after_packets,
QuicTime::Delta yield_after_duration,
const NetLogWithSource& net_log);
...
}
(4) 调用Connect()连接服务器
在UDP套接字打开的情况下,打开QUIC连接并连接到服务器,包括执行同步加密握手。
-
调用StartConnect()函数: 首先创建一个QuicPacketWriter用于写数据到quic数据包中,接着调用CreateQuicClientSession创建session并初始化session,启动加密握手并等待完成。【一个疑惑是这里已经对session进行了加密处理。并且session和stream以及UDP链接之间的区别是什么?此外,并且这一步已经向服务器发送和CHLO数据包。】
-
进入while循环,调用WaitForEvents() 函数循环等待服务端的响应。WaitForEvents()函数会调用一个RunLoop()函数。【不太清楚RunLoop的作用机制】
-
服务器链接成功后会打印相关的信息
(5) 数据发送
调用SendRequestAndWaitForResponse()函数来发送请求并等待响应
-
要发送数据,客户端调用SendRequest方法,需要创建 QuicSpdyClientStream类 实例。 新的QUIC流QuicSpdyClientStream实例必须由CreateReliableClientStream方法调用会话的CreateOutgoingDynamicStream方法创建,因为新的流( stream )必须调用会话的基类( QuicSession类 )中受保护( protected )的ActivateStream方法。
-
在添加并激活信的流后,客户端的SendRequest方法最后会调用QuicSpdyClientStream类的SendRequest方法会调用流基类ReliableQuicStream类中的WriteOrBufferData方法将数据写入流 ( stream )。
void QuicClientBase::SendRequest(const SpdyHeaderBlock& headers,
StringPiece body,
bool fin) {
...
QuicSpdyClientStream* stream = CreateReliableClientStream();
if (stream == nullptr) {
QUIC_BUG << "stream creation failed!";
return;
}
stream->SendRequest(headers.Clone(), body, fin);
// Record this in case we need to resend.
MaybeAddDataToResend(headers, body, fin);
}
QuicSpdyClientStream* QuicClientBase::CreateReliableClientStream() {
if (!connected()) {
return nullptr;
}
QuicSpdyClientStream* stream =
session_->CreateOutgoingDynamicStream(kDefaultPriority);
if (stream) {
// set QuicSimpleClient as the vistor
stream->set_visitor(this);
}
return stream;
}
QuicSpdyClientStream* QuicClientSession::CreateOutgoingDynamicStream(
SpdyPriority priority) {
if (!ShouldCreateOutgoingDynamicStream()) {
return nullptr;
}
std::unique_ptr<QuicSpdyClientStream> stream = CreateClientStream();
stream->SetPriority(priority);
QuicSpdyClientStream* stream_ptr = stream.get();
ActivateStream(std::move(stream));
return stream_ptr;
}
std::unique_ptr<QuicSpdyClientStream> QuicClientSession::CreateClientStream() {
return base::MakeUnique<QuicSpdyClientStream>(GetNextOutgoingStreamId(),
this);
}
void QuicSession::ActivateStream(std::unique_ptr<ReliableQuicStream> stream) {
QuicStreamId stream_id = stream->id();
DVLOG(1) << ENDPOINT << "num_streams: " << dynamic_stream_map_.size()
<< ". activating " << stream_id;
DCHECK(!base::ContainsKey(dynamic_stream_map_, stream_id));
DCHECK(!base::ContainsKey(static_stream_map_, stream_id));
dynamic_stream_map_[stream_id] = std::move(stream);
if (IsIncomingStream(stream_id)) {
++num_dynamic_incoming_streams_;
}
// Increase the number of streams being emulated when a new one is opened.
connection_->SetNumOpenStreams(dynamic_stream_map_.size());
}
size_t QuicSpdyClientStream::SendRequest(SpdyHeaderBlock headers,
StringPiece body,
bool fin) {
bool send_fin_with_headers = fin && body.empty();
size_t bytes_sent = body.size();
header_bytes_written_ =
WriteHeaders(std::move(headers), send_fin_with_headers, nullptr);
bytes_sent += header_bytes_written_;
if (!body.empty()) {
WriteOrBufferData(body, fin, nullptr);
}
return bytes_sent;
}
- 在发送请求以后,客户端需要等待接受数据。调用WaitForEvents读取Socket数据并进行处理。
bool QuicClientBase::WaitForEvents() {
DCHECK(connected());
RunEventLoop();
DCHECK(session() != nullptr);
if (!connected() &&
session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
DCHECK(FLAGS_enable_quic_stateless_reject_support);
DVLOG(1) << "Detected stateless reject while waiting for events. "
<< "Attempting to reconnect.";
Connect();
}
return session()->num_active_requests() != 0;
}
void QuicSimpleClient::RunEventLoop() {
StartPacketReaderIfNotStarted();
base::RunLoop().RunUntilIdle();
}
void QuicSimpleClient::StartPacketReaderIfNotStarted() {
if (!packet_reader_started_) {
packet_reader_->StartReading();
packet_reader_started_ = true;
}
}
void QuicChromiumPacketReader::StartReading() {
if (read_pending_)
return;
if (num_packets_read_ == 0)
yield_after_ = clock_->Now() + yield_after_duration_;
DCHECK(socket_);
read_pending_ = true;
int rv = socket_->Read(read_buffer_.get(), read_buffer_->size(),
base::Bind(&QuicChromiumPacketReader::OnReadComplete,
weak_factory_.GetWeakPtr()));
UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.AsyncRead", rv == ERR_IO_PENDING);
if (rv == ERR_IO_PENDING) {
num_packets_read_ = 0;
return;
}
if (++num_packets_read_ > yield_after_packets_ ||
clock_->Now() > yield_after_) {
num_packets_read_ = 0;
// Data was read, process it.
// Schedule the work through the message loop to 1) prevent infinite
// recursion and 2) avoid blocking the thread for too long.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&QuicChromiumPacketReader::OnReadComplete,
weak_factory_.GetWeakPtr(), rv));
} else {
OnReadComplete(rv);
}
void QuicChromiumPacketReader::OnReadComplete(int result) {
read_pending_ = false;
if (result == 0)
result = ERR_CONNECTION_CLOSED;
if (result < 0) {
visitor_->OnReadError(result, socket_);
return;
}
QuicReceivedPacket packet(read_buffer_->data(), result, clock_->Now());
IPEndPoint local_address;
IPEndPoint peer_address;
socket_->GetLocalAddress(&local_address);
socket_->GetPeerAddress(&peer_address);
if (!visitor_->OnPacket(packet, local_address, peer_address))
return;
StartReading();
}
- 此外,客户端还必须读取通知的UDP数据包。QuicChromiumPacketReader::OnReadComplete 方法会注册为Socket的回调函数,继而调用客户端的OnPacket方法。所以客户端实现了 QuicChromiumPacketReader::Visitor接口的OnPacket方法。当成功读取QUIC包时,必须使用ProcessUdpPacket方法将其分派到QuicConnection中,最终 会交给QuicFramer类的ProcessPacket方法处理。
bool QuicSimpleClient::OnPacket(const QuicReceivedPacket& packet,
IPEndPoint local_address,
IPEndPoint peer_address) {
session()->connection()->ProcessUdpPacket(local_address, peer_address,
packet);
if (!session()->connection()->connected()) {
return false;
}
return true;
}
void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
const QuicReceivedPacket& packet) {
if (!connected_) {
return;
}
if (debug_visitor_ != nullptr) {
debug_visitor_->OnPacketReceived(self_address, peer_address, packet);
}
last_size_ = packet.length();
current_packet_data_ = packet.data();
last_packet_destination_address_ = self_address;
last_packet_source_address_ = peer_address;
if (!IsInitializedIPEndPoint(self_address_)) {
self_address_ = last_packet_destination_address_;
}
if (!IsInitializedIPEndPoint(peer_address_)) {
peer_address_ = last_packet_source_address_;
}
stats_.bytes_received += packet.length();
++stats_.packets_received;
// Ensure the time coming from the packet reader is within a minute of now.
if (FLAGS_quic_allow_large_send_deltas &&
std::abs((packet.receipt_time() - clock_->ApproximateNow()).ToSeconds()) >
60) {
QUIC_BUG << "Packet receipt time:"
<< packet.receipt_time().ToDebuggingValue()
<< " too far from current time:"
<< clock_->ApproximateNow().ToDebuggingValue();
}
time_of_last_received_packet_ = packet.receipt_time();
DVLOG(1) << ENDPOINT << "time of last received packet: "
<< time_of_last_received_packet_.ToDebuggingValue();
ScopedRetransmissionScheduler alarm_delayer(this);
if (!framer_.ProcessPacket(packet)) {
// If we are unable to decrypt this packet, it might be
// because the CHLO or SHLO packet was lost.
if (framer_.error() == QUIC_DECRYPTION_FAILURE) {
if (encryption_level_ != ENCRYPTION_FORWARD_SECURE &&
undecryptable_packets_.size() < max_undecryptable_packets_) {
QueueUndecryptablePacket(packet);
} else if (debug_visitor_ != nullptr) {
debug_visitor_->OnUndecryptablePacket();
}
}
DVLOG(1) << ENDPOINT << "Unable to process packet. Last packet processed: "
<< last_header_.packet_number;
current_packet_data_ = nullptr;
return;
}
++stats_.packets_processed;
if (active_peer_migration_type_ != NO_CHANGE &&
sent_packet_manager_->GetLargestObserved(last_header_.path_id) >
highest_packet_sent_before_peer_migration_) {
OnPeerMigrationValidated(last_header_.path_id);
}
MaybeProcessUndecryptablePackets();
MaybeSendInResponseToPacket();
SetPingAlarm();
current_packet_data_ = nullptr;
}
- 此外,当Stream收到FIN标志为1的帧后会调用Stream->OnClose()方法,继而会调用 QuicSimpleClient(即QuicClientBase)的OnClose方法,取出Stream中收到的HTTP响应头部和数据。所以客户端实现了QuicSpdyStream::Visitor接口中的OnClose方法。
void QuicClientBase::OnClose(QuicSpdyStream* stream) {
DCHECK(stream != nullptr);
QuicSpdyClientStream* client_stream =
static_cast<QuicSpdyClientStream*>(stream);
const SpdyHeaderBlock& response_headers = client_stream->response_headers();
if (response_listener_ != nullptr) {
response_listener_->OnCompleteResponse(stream->id(), response_headers,
client_stream->data());
}
// Store response headers and body.
if (store_response_) {
auto status = response_headers.find(":status");
if (status == response_headers.end() ||
!StringToInt(status->second, &latest_response_code_)) {
LOG(ERROR) << "Invalid response headers";
}
latest_response_headers_ = response_headers.DebugString();
latest_response_header_block_ = response_headers.Clone();
latest_response_body_ = client_stream->data();
latest_response_trailers_ =
client_stream->received_trailers().DebugString();
}
}
服务端的实现
1. 服务端实现的具体流程
(1) 代码中函数的一个整体调用流程:
(2) 服务端的一个整体框架
此块的解读有待验证
服务端是基于even loop的设计思想来实现的,但是整个服务器是一个单线程的结构。服务端整体的框架如下图所示:
在上述过程中OnReadComplete被注册为回调函数来负责新链接的接入和新的新数据的读取。整个结构的实现是一个单线程阻塞式的设计。
2. 重要函数
2.1 ProcessBufferedChlos函数的
在整个处理过程中,连接id是如何得到的,端上生成?
/*
* ProcessBufferChlos处理逻辑:
* 实例化server_connection_id
* 调用DeliverPacketsForNextConnection查看在缓冲队列中的chlo及其连接id,将该连接id赋值给server_connection_id并返回该连接id的其他缓冲数据包
* 调用MaybeReplaceServerConnectionId函数验证ID的长度是否符合dispacher_的要求,如果不符合需要对server_connection_id的长度进行变更
* 基于创建的server_id创建session
* 对original_connection_id和server_connection_id进行比对
* 将创建的connection_id和session插入session_map
*/
void QuicDispatcher::ProcessBufferedChlos(size_t max_connections_to_create) {
// Reset the counter before starting creating connections.
new_sessions_allowed_per_event_loop_ = max_connections_to_create;
for (; new_sessions_allowed_per_event_loop_ > 0;
--new_sessions_allowed_per_event_loop_) {
QuicConnectionId server_connection_id;
BufferedPacketList packet_list =
buffered_packets_.DeliverPacketsForNextConnection(
&server_connection_id);
const std::list<BufferedPacket>& packets = packet_list.buffered_packets;
if (packets.empty()) {
return;
}
QuicConnectionId original_connection_id = server_connection_id;
// MMaybeReplaceServerConnectionId:验证ID的长度是否符合dispacher_的要求,如果不符合需要对其进行变更
server_connection_id = MaybeReplaceServerConnectionId(server_connection_id,
packet_list.version);
std::string alpn = SelectAlpn(packet_list.alpns);
std::unique_ptr<QuicSession> session = CreateQuicSession(
server_connection_id, packets.front().self_address,
packets.front().peer_address, alpn, packet_list.version);
// 此处的逻辑没太清楚
if (original_connection_id != server_connection_id) {
session->connection()->SetOriginalDestinationConnectionId(
original_connection_id);
}
QUIC_DLOG(INFO) << "Created new session for " << server_connection_id;
if (use_reference_counted_session_map_) {
auto insertion_result = reference_counted_session_map_.insert(
std::make_pair(server_connection_id,
std::shared_ptr<QuicSession>(std::move(session))));
if (!insertion_result.second) {
QUIC_BUG
<< "Tried to add a session to session_map with existing connection "
"id: "
<< server_connection_id;
} else if (support_multiple_cid_per_connection_) {
++num_sessions_in_session_map_;
}
DeliverPacketsToSession(packets, insertion_result.first->second.get());
} else {
auto insertion_result = session_map_.insert(
std::make_pair(server_connection_id, std::move(session)));
QUIC_BUG_IF(!insertion_result.second)
<< "Tried to add a session to session_map with existing connection "
"id: "
<< server_connection_id;
// 把packet传输到sessio中进一步处理
DeliverPacketsToSession(packets, insertion_result.first->second.get());
}
}
}
2.2 ProcesChlo函数
该函数就是真正的对Chlo处理的函数
2.3 ProcessUdpPacket函数
该函数中调用了frame_.ProcessPacket函数
- frame_.ProcessPacket(packet)对数据包进行处理
- ProcessPacket函数调用了ProcessPacketInternal
- 其中的ProcessPacketInternal是QuicFramer类中的的一个成员函数
- ProcessPacketInternal函数会调用ProcessIeftDataPaket进而再调用ProcessIetfDataFrame函数按照帧的类型对帧进行处理。也就是在此处对各个帧进行处理
被引用关系
- ProcessUdpPacket被ProcessPacket函数调用
- ProcessPacket被OnReadComplete调用
- OnReadComplete被StartReading调用,并且被设计为了回调函数
- StartReading被Listen函数调用,Listen就是用来监听是否有新的客户端连接进来。
2.4 OnReadComplete函数
该函数在StartReading函数中被注册为回调函数。当有新的客户端接入或者新的数据到来时就会触发该函数,该函数中又调用了StartReading函数对新的帧包进行接收。
// 该段代码位于StratReading函数中
if (result == ERR_IO_PENDING) {
synchronous_read_count_ = 0;
if (dispatcher_->HasChlosBuffered()) {
// No more packets to read, so yield before processing buffered packets.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&QuicSimpleServer::StartReading, // 在此处被注册为回调函数
weak_factory_.GetWeakPtr()));
}
return;
}
OnReadComplete函数的定义:
void QuicSimpleServer::OnReadComplete(int result) {
// 当前线程没有被挂起,直接进行数据的处理,处理后再进入下一个startReading
read_pending_ = false;
if (result > 0) {
quic::QuicReceivedPacket packet(read_buffer_->data(), result,
helper_->GetClock()->Now(), false);
// dispatcher_是事件分发器,在这里调用处理包方法
dispatcher_->ProcessPacket(ToQuicSocketAddress(server_address_),
ToQuicSocketAddress(client_address_), packet);
} else {
LOG(ERROR) << "QuicSimpleServer read failed: " << ErrorToString(result);
// Do not act on ERR_MSG_TOO_BIG as that indicates that we received a UDP
// packet whose payload is larger than our receive buffer. Do not act on 0
// as that indicates that we received a UDP packet with an empty payload.
// In both cases, the socket should still be usable.
if (result != ERR_MSG_TOO_BIG && result != 0) {
Shutdown();
return;
}
}
StartReading();
}