Chromium源码解读--客户端和服务端实现

参考文献

[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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值