写数据
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;
}