模拟网站平台怎么做,建材类网站建设需要的资料,asp网站攻击,珠海网站建设技术托管一.基础概念
1.TCPSender在TCPSocket中的地位与作用 Lab0中实现了基于内存模拟的流控制-字节流#xff08;ByteStream#xff09;#xff0c;底层使用std::deque实现#xff0c;根据最大容量Capacity进行容量控制。个人理解它相当于应用层的输入输出缓存区#xff0c;用户…一.基础概念
1.TCPSender在TCPSocket中的地位与作用 Lab0中实现了基于内存模拟的流控制-字节流ByteStream底层使用std::deque实现根据最大容量Capacity进行容量控制。个人理解它相当于应用层的输入输出缓存区用户依托Socket发送数据读取数据。都要先将数据推入缓存区中例如使用TCP发送数据用户需要先将数据推入ByteStream中TCPSender根据滑动窗口当前长度从ByteStream中读取一定数量的数据之后再进行协议封装最后推入发送队列中。TCPSender就是执行bytestream到Tcpsegment的工具。值得注意的是这个转换过程应该是自动执行的且存在滑动窗口流量控制与超时重传机制。LAB4中将会实现TCPConnection他包括TCPSender与TCPReceiver。 从图中知道bytestream需要转换为TCPSegment需要添加协议头添加序列号SYNpayload以及FIN标志位。根据接收端接收到的ackno与window_size确定滑动窗口长度进行流量控制。故而要实现TCPSender时可发送的数据范围由接收端给出的滑动窗口长度决定。协议头的标志位由当前TCPSender的状态决定。
2.何为端到端模型 Lab3原文如下 TCP is a protocol that reliably conveys a pair of flow-controlled byte streams (one in each direction) over unreliable datagrams. Two parties participate in the TCP connection, and each party acts as both “sender” (of its own outgoing byte-stream) and “receiver” (of an incoming byte-stream) at the same time. The two parties are called the “endpoints” of the connection, or the “peers. 端到端是网络连接。 网络要通信必须建立连接不管有多远中间有多少机器都必须在两头源和目的间建立连接一旦连接建立起来就说已经是端到端连接了即端到端是逻辑链路这条路可能经过了很复杂的物理路线但两端主机不管只认为是有两端的连接而且一旦通信完成这个连接就释放了物理线路可能又被别的应用用来建立连接了。简而言之端到端的通信只要要处理好对应层内的协议就好了且两端需要对等协议需要具备普适性。一切优化更改都需要在其上一层进行本层只负责本层的事务。我们要保证两个端点的行为一致性。 It’s important to remember that the receiver can be any implementation of a valid TCP receiver—it won’t necessarily be your own TCPReceiver. One of the valuable things about Internet standards is how they establish a common language between endpoints that may otherwise act very differently.
3.TCP协议头格式 TCPSender负责组装的TCPSegment格式见上图发送端主要关注其中蓝色部分即可。序列号FIN以及SYN标志与载荷数据。相对应的接收端需要关注红色部分。
3.ARQ The basic principle is to send whatever the receiver will allow us to send (filling the window), and keep retransmitting until the receiver acknowledges each segment. This is called “automatic repeat request” (ARQ). The sender divides the byte stream up into segments and sends them, as much as the receiver’s window allows.
4.TCP如何知道消失丢失超时重传机制 TCPSender在发送消失时会对已经发送的Segment进行一个缓存备份我得TCPSender实现中使用了一个FIFO队列进行管理。只有当确认号大于缓存区中Segment的序列号时才进行出队操作。总而言之我们追踪了滑动窗口发送的每一个Segment的序列号与其内容。通过确认号与序列号以及超时时间RTO来判断数据是否丢失。是否选择重传。
LAB3原文 需要注意的是如果超时事件发生且窗口长度非0需要将RTO时间加倍这是因为在窗长非0时出现了数据丢失那么当前网络拥塞较为严重为了避免快速重传导致网络负载加倍可以降低重传速率。 超时重传定时器的状态在RFC官方文档中有详细说明如下所示 这里面有几个坑 1.重传计时器在窗口发送时如果没有启动则会重新启动。这里注意并不是每发送一个数据包就启动一次定时器对每一个数据包进行计时开销是极其大的。启动定时器是为了对存入重传缓冲区的数据进行计时如果重传缓冲区空了就要关闭计时器发送时将数据压入缓冲区这时如果定时器未启动则启动定时器。
2.当收到新的ACK序号必须大于之前的ACK序号会进行定时器更新具体为清除重传计数恢复RTO时间。清除缓存区已经确认的数据。
3.如果重传事件发生且窗长大于0那么必须使RTO加倍。 总结一下定时器有三种状态分别为启动、停止、超时。只有在新数据推入且定时器未开启的时候会启动定时器只有在重传缓冲区没有数据时会关闭定时器超时发生时如果窗长大于0那么RTO必须加倍。立即定时器的三个状态时Lab3最重要的一点。
二.具体实现
1.TCP发送状态转移 要完成Lab3需要很好的理解下图理解了发送的状态转移有助于在写发送窗口时理清楚条件设置如下所示 CLOSED:此时未发送SYN同步标志如果在这个状态那么发送SYN
SYN_SENT:此时已经发送SYN但是没有收到ACK这时要做的就是等待
SYN_ACKED1:此时收到ACK可以正常收发数据根据窗口大小划分数据包尽可能向发送队列写入数据
SYN_ACKED2:此时发送stream已经到达EOF但是FIN还未发送需要发送FIN
发送了FIN后窗口将不在发送新数据此时应该保证fill_window函数不做任何事情。具体代码实现如下
void TCPSender::fill_window()
{// CLOSED (waiting for stream to begin no SYN sent)if (next_seqno_absolute() 0){// send SYN_send_segment(, true);return;}// SYN_SEND (stream started but nothing acknowledged)else if (next_seqno_absolute() 0 next_seqno_absolute() bytes_in_flight()){return;}size_t cur_window_size (_window_size 0) ? 1 : _window_size;while (cur_window_size bytes_in_flight()){// SYN_ACKED (stream ongoing)if (next_seqno_absolute() bytes_in_flight() !stream_in().eof()){// flag for send successbool success_send false;size_t payload_size min(TCPConfig::MAX_PAYLOAD_SIZE,cur_window_size - bytes_in_flight());string payload move(_stream.read(payload_size));// stream reached EOF and remaining window size can insert FIN flagif (stream_in().eof() cur_window_size - bytes_in_flight() - payload.size() 0)success_send _send_segment(move(payload), false, true);elsesuccess_send _send_segment(move(payload));// Nothing to send cause segment length is zore,break.if (!success_send) break;}else if (stream_in().eof()){// SYN_ACK (stream ongoing, stream has reached EOF, but FIN flag hasnt been sent yet)if (next_seqno_absolute() stream_in().bytes_written() 2){_send_segment(, false, true);}else// FIN_SENTbreak;}}
} 2.ack接收部分 最难的发送部分实现完毕这个较为简单
//! \param ackno The remote receivers ackno (acknowledgment number)
//! \param window_size The remote receivers advertised window size
void TCPSender::ack_received(const WrappingInt32 ackno, const uint16_t window_size)
{// update window size_window_size window_size;// get 64-bit absolute acknouint64_t abs_ackno unwrap(ackno, _isn, _last_ackno);// if something impossible returnif (abs_ackno next_seqno_absolute()) return;// if ackno is new ack, check retrans bufferif (abs_ackno _last_ackno){// update new 64-bit ackno_last_ackno abs_ackno;while (!_flight_buffer.empty()){const TCPSegment seg _flight_buffer.front();if (seg.header().seqno.raw_value() seg.length_in_sequence_space() ackno.raw_value())_flight_buffer.pop();elsebreak;}// update timer setting_consecutive_retransmissions_count 0;_rto _initial_retransmission_timeout;if (!_flight_buffer.empty())_timer.start(_rto);else_timer.stop();}fill_window();
}3.重传部分
//! \param[in] ms_since_last_tick the number of milliseconds since the last call to this method
void TCPSender::tick(const size_t ms_since_last_tick)
{// timer elapse_timer.tick(ms_since_last_tick);// if timer out and retrans buffer is not emptyif (_timer.is_expired() !_flight_buffer.empty()){// retrans_segments_out.push(_flight_buffer.front());// window size has odd cause of internets bad status, double RTOif (_window_size 0){_rto * 2;_consecutive_retransmissions_count;//std::cout _consecutive_retransmissions_count std::endl;}_timer.start(_rto);}else if (_flight_buffer.empty()){_timer.stop();}
}个人复盘请勿传播引用。