posix_quic-master写数据函数

本文深入探讨了QUIC协议中数据写入的具体流程,包括QuicWrite、QuicWritev、WritevData等关键函数的实现细节,以及数据如何通过缓冲区管理和流控机制最终发送出去。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写数据

 res = QuicWrite(stream, s.c_str(), s.size(), false);

跟进这个QuicWrite()函数
//传入stream,数据 数据的长度 一个bool类型的参数 fin 是否终止

ssize_t QuicWrite(QuicStream stream, const void* data, size_t length, bool fin)
{
    struct iovec iov;
    iov.iov_base = (void*)data;
    iov.iov_len = length;
    return QuicWritev(stream, &iov, 1, fin); //只穿进去一个结构体
}

/* Structure for scatter/gather I/O. */

struct iovec
  {
    void *iov_base;	/* Pointer to data.  *///指向这个数据
    size_t iov_len;	/* Length of data.  *///指向数据的长度 这是一个结构体
  };

跟进这个QuicWritev()函数

ssize_t QuicWritev(QuicStream stream, const struct iovec* iov, int iov_count, bool fin)
{
    auto streamPtr = EntryBase::GetFdManager().Get(stream);//根据流从map中查找指针
    if (!streamPtr || streamPtr->Category() != EntryCategory::Stream) {
        DebugPrint(dbg_api, "stream = %d, return = -1, errno = EBADF", stream);
        errno = EBADF;
        return -1;
    }

    ssize_t res = ((QuicStreamEntry*)streamPtr.get())->Writev(iov, iov_count, fin);
    DebugPrint(dbg_api, "stream = %d, return = %ld, errno = %d", stream, res, errno);
    return res;
}

//写数据的是Writev函数

ssize_t QuicStreamEntry::Writev(const struct iovec* iov, size_t iov_count, bool fin)
{
    if (Error()) {
        DebugPrint(dbg_write, "stream = %d, Has error = %d", Fd(), Error());
        errno = Error();
        return -1;
    }

    auto stream = GetQuartcStream();//先获取这个stream
    if (!stream) {
        DebugPrint(dbg_write, "stream = %d, GetQuartcStream returns nullptr", Fd());
        errno = EBADF;
        return -1;
    }

    QuicConsumedData resData = stream->WritevData(iov, iov_count, fin);//将数据写出去
    if (resData.bytes_consumed == 0) {
        errno = EAGAIN;
        return -1;
    }

    errno = 0;
    return resData.bytes_consumed;
}

//跟进这个写数据WritevData()

QuicConsumedData QuartcStream::WritevData(const struct iovec* iov,
        int iov_count, bool fin)
{
    return QuicStream::WritevData(iov, iov_count, fin);//调用了流的这个函数
}
//转入到流的写数据中QuicStream::WritevData()

QuicConsumedData QuicStream::WritevData(const struct iovec* iov,
                                        int iov_count,
                                        bool fin) {
  if (write_side_closed_){ //判断写端是否关闭
    QUIC_DLOG(ERROR) << ENDPOINT << "Stream " << id()
                     << "attempting to write when the write side is closed";
    return QuicConsumedData(0, false);//也就是0个数据写入 
  }
  //判断传入字符的长度
  // How much data was provided.
  size_t write_length = 0;
  if (iov != nullptr) {
  //通过累加的方式判断总共传入的字节长度,可以看到是把传入的结构体iov中的每个iov_len累加起来
    for (int i = 0; i < iov_count; ++i) {
      write_length += iov[i].iov_len;
    }
  }
//判断缓冲区是否已经满了
  QuicConsumedData consumed_data(0, false);
  if (fin_buffered_) {
    QUIC_BUG << "Fin already buffered";
    return consumed_data;
  }
// kMaxStreamLength  The max length a stream can have.
//Send buffer of this stream. Send buffer is cleaned up when data gets acked
// or discarded.
  if (GetQuicReloadableFlag(quic_stream_too_long) &&
      kMaxStreamLength - send_buffer_.stream_offset() < write_length) {//如果剩余的空间小于要写入的字节量
    QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_stream_too_long, 2, 5);
    QUIC_BUG << "Write too many data via stream " << id_;
    CloseConnectionWithDetails(//如果传入的数据过大 那么将会关闭连接
        QUIC_STREAM_LENGTH_OVERFLOW,
        QuicStrCat("Write too many data via stream ", id_));
    return consumed_data;
  }
//队列中有等待缓存的数据
  bool had_buffered_data = HasBufferedData();
  //if bufferedd data in send buff is below  buffered_data_threshold
  if (CanWriteNewData()) {
    // Save all data if buffered data size is below low water mark.
    consumed_data.bytes_consumed = write_length;
    if (consumed_data.bytes_consumed > 0) {
      QuicStreamOffset offset = send_buffer_.stream_offset();
      send_buffer_.SaveStreamData(iov, iov_count, 0, write_length);
      OnDataBuffered(offset, write_length, nullptr);
    }
  }
  consumed_data.fin_consumed =
      consumed_data.bytes_consumed == write_length && fin;
  fin_buffered_ = consumed_data.fin_consumed;

  if (!had_buffered_data && (HasBufferedData() || fin_buffered_)) {
    // Write data if there is no buffered data before.
    WriteBufferedData();//把缓冲区的数据写出去
  }

  return consumed_data;
}

HasBufferedData() 判断queue队列中是否有缓存的数据

bool QuicStream::HasBufferedData() const {
  DCHECK_GE(send_buffer_.stream_offset(), stream_bytes_written());
  return send_buffer_.stream_offset() > stream_bytes_written();
}

//把数据保存到数据缓冲区

void QuicStreamSendBuffer::SaveStreamData(const struct iovec* iov,
                                          int iov_count,
                                          size_t iov_offset,
                                          QuicByteCount data_length) {
  DCHECK_LT(0u, data_length);
  // Latch the maximum data slice size.
  const QuicByteCount max_data_slice_size =
      GetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size);
  while (data_length > 0) {
    size_t slice_len = std::min(data_length, max_data_slice_size);
    QuicMemSlice slice(allocator_, slice_len);
    QuicUtils::CopyToBuffer(iov, iov_count, iov_offset, slice_len,
                            const_cast<char*>(slice.data()));//复制数据
    SaveMemSlice(std::move(slice));
    data_length -= slice_len;
    iov_offset += slice_len;
  }
}

//跟踪一下这个WriteBufferedData() 把缓冲区的数据发送出去

void QuicStream::WriteBufferedData() {
  DCHECK(!write_side_closed_ && (HasBufferedData() || fin_buffered_));

  if (session_->ShouldYield(id())) {
    session_->MarkConnectionLevelWriteBlocked(id());
    return;
  }

  // Size of buffered data. //查看缓冲区的数据大小
  size_t write_length = BufferedDataBytes();

  // A FIN with zero data payload should not be flow control blocked.
  bool fin_with_zero_data = (fin_buffered_ && write_length == 0);

  bool fin = fin_buffered_;

  // How much data flow control permits to be written.  允许发送的最大数据
//也就是发送窗口
  QuicByteCount send_window = flow_controller_.SendWindowSize();
  if (stream_contributes_to_connection_flow_control_) {
    send_window =
        std::min(send_window, connection_flow_controller_->SendWindowSize());
  }

  if (send_window == 0 && !fin_with_zero_data) {
    // Quick return if nothing can be sent.
    MaybeSendBlocked();//如果没有数据发送 ,可能会是发送数据阻塞
    return;
  }

  if (write_length > send_window) {//如果发送额数据比发送窗口要大
    // Don't send the FIN unless all the data will be sent.
    fin = false;

    // Writing more data would be a violation of flow control.
    write_length = static_cast<size_t>(send_window);//就将发送数据设置为流控的数据大小
    QUIC_DVLOG(1) << "stream " << id() << " shortens write length to "
                  << write_length << " due to flow control";
  }
  if (session_->session_decides_what_to_write()) {
    session_->SetTransmissionType(NOT_RETRANSMISSION);
  }
  QuicConsumedData consumed_data =
      WritevDataInner(write_length, stream_bytes_written(), fin);

  OnStreamDataConsumed(consumed_data.bytes_consumed);

  AddBytesSent(consumed_data.bytes_consumed);
  QUIC_DVLOG(1) << ENDPOINT << "stream " << id_ << " sends "
                << stream_bytes_written() << " bytes "
                << " and has buffered data " << BufferedDataBytes() << " bytes."
                << " fin is sent: " << consumed_data.fin_consumed
                << " fin is buffered: " << fin_buffered_;

  // The write may have generated a write error causing this stream to be
  // closed. If so, simply return without marking the stream write blocked.
  if (write_side_closed_) {
    return;
  }

  if (consumed_data.bytes_consumed == write_length) {
    if (!fin_with_zero_data) {
      MaybeSendBlocked();
    }
    if (fin && consumed_data.fin_consumed) {
      fin_sent_ = true;
      fin_outstanding_ = true;
      if (fin_received_) {
        session_->StreamDraining(id_);
      }
      CloseWriteSide();
    } else if (fin && !consumed_data.fin_consumed) {
      session_->MarkConnectionLevelWriteBlocked(id());
    }
  } else {
    session_->MarkConnectionLevelWriteBlocked(id());
  }
  if (consumed_data.bytes_consumed > 0 || consumed_data.fin_consumed) {
    busy_counter_ = 0;
  }
}

//写数据
WritevDataInner(write_length, stream_bytes_written(), fin);

QuicConsumedData QuicStream::WritevDataInner(size_t write_length,
                                             QuicStreamOffset offset,
                                             bool fin) {
  StreamSendingState state = fin ? FIN : NO_FIN;
  if (fin && add_random_padding_after_fin_) {
    state = FIN_AND_PADDING;
  }
  return session()->WritevData(this, id(), write_length, offset, state);
}

//把数据发送出去
return session()->WritevData(this, id(), write_length, offset, state);

QuicConsumedData QuicSession::WritevData(QuicStream* stream,
                                         QuicStreamId id,
                                         size_t write_length,
                                         QuicStreamOffset offset,
                                         StreamSendingState state) {
  // This check is an attempt to deal with potential memory corruption
  // in which |id| ends up set to 1 (the crypto stream id). If this happen
  // it might end up resulting in unencrypted stream data being sent.
  // While this is impossible to avoid given sufficient corruption, this
  // seems like a reasonable mitigation.
  if (id == kCryptoStreamId && stream != GetMutableCryptoStream()) {
    QUIC_BUG << "Stream id mismatch";
    RecordInternalErrorLocation(QUIC_SESSION_WRITEV_DATA);
    connection_->CloseConnection(
        QUIC_INTERNAL_ERROR,
        "Non-crypto stream attempted to write data as crypto stream.",
        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
    return QuicConsumedData(0, false);
  }
  if (!IsEncryptionEstablished() && id != kCryptoStreamId) {
    // Do not let streams write without encryption. The calling stream will end
    // up write blocked until OnCanWrite is next called.
    return QuicConsumedData(0, false);
  }
  if (connection_->encryption_level() != ENCRYPTION_FORWARD_SECURE) {
    // Set the next sending packets' long header type.
    QuicLongHeaderType type = ZERO_RTT_PROTECTED;
    if (id == kCryptoStreamId) {
      type = GetCryptoStream()->GetLongHeaderType(offset);
    }
    connection_->SetLongHeaderType(type);
  }
  QuicConsumedData data =
      connection_->SendStreamData(id, write_length, offset, state);
  if (offset >= stream->stream_bytes_written()) {
    // This is new stream data.
    write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed);
  }
  return data;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值