抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Lab2

wrapping_int32

实现序列号、绝对序列号与流索引间的转换。

出现cmake报错为:

1
2
3
4
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
LIBPCAP
linked by target "tcp_parser" in directory /home/kangyu/sponge/testslinked by target "tcp_parser" in directory /home/ryao/Projects/cppProjects/CS144Labs/tests

需要安装libpcap-dev库来解决. apt install libpcap-dev

文段中指出了三种序列的关系,其中stream indices就是在lab1中的序列。

照着写就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
WrappingInt32 wrap(uint64_t n, WrappingInt32 isn) {
// uint64_t m = (1ll << 32);
// uint32_t num = (n + isn.raw_value()) % m;
// return WrappingInt32{num};
return WrappingInt32{isn.raw_value() + static_cast<uint32_t>(n)};
}

//! Transform a WrappingInt32 into an "absolute" 64-bit sequence number (zero-indexed)
//! \param n The relative sequence number
//! \param isn The initial sequence number
//! \param checkpoint A recent absolute 64-bit sequence number
//! \returns the 64-bit sequence number that wraps to `n` and is closest to `checkpoint`
//!
//! \note Each of the two streams of the TCP connection has its own ISN. One stream
//! runs from the local TCPSender to the remote TCPReceiver and has one ISN,
//! and the other stream runs from the remote TCPSender to the local TCPReceiver and
//! has a different ISN.
uint64_t unwrap(WrappingInt32 n, WrappingInt32 isn, uint64_t checkpoint) {
uint32_t offset = n.raw_value() - isn.raw_value();
uint64_t t = (checkpoint & 0xFFFFFFFF00000000) + offset;
uint64_t ret = t;
if (abs(int64_t(t + (1ul << 32) - checkpoint)) < abs(int64_t(t - checkpoint))) {
ret = t + (1ul << 32);
}
if (t >= (1ul << 32) && abs(int64_t(t - (1ul << 32) - checkpoint)) < abs(int64_t(ret - checkpoint))) {
ret = t - (1ul << 32);
}
return ret;
}

ctest -R wrap 进行测试

tcp_receiver

实现tcp的接收端。

要求为:

In the rest of this lab, you’ll be implementing the TCPReceiver. It will (1) receive segments from its peer, (2) reassemble the ByteStream using your StreamReassembler, and calculate the (3) acknowledgment number (ackno) and (4) the window size.

需要实现segment_received(const TCPSegment &seg)ackno()window_size(),具体的要求在文档(https://cs144.github.io/assignments/lab2.pdf)里写的很清楚。

总体还是很简单的。

需要注意的有:

  1. ackno(): 对于SYN FIN 是需要单独占两个位置的 如果SYN出现了 需要+1 如果FIN也出现了 就需要再+1

tcp_receiver.hh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class TCPReceiver {
//! Our data structure for re-assembling bytes.
StreamReassembler _reassembler;
uint64_t _abs_seqno;
WrappingInt32 _isn;
bool _syn_flag;

//! The maximum number of bytes we'll store.
size_t _capacity;

public:
//! \brief Construct a TCP receiver
//!
//! \param capacity the maximum number of bytes that the receiver will
//! store in its buffers at any give time.
TCPReceiver(const size_t capacity)
: _reassembler(capacity)
, _abs_seqno(0)
, _isn(0)
, _syn_flag(false)
, _capacity(capacity) {}

tcp_receiver.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void TCPReceiver::segment_received(const TCPSegment &seg) {
const TCPHeader &header = seg.header();
// 判断是否是 SYN 包
if (header.syn) {
_isn = header.seqno;
_syn_flag = true;
_abs_seqno = 0;
} else if (!_syn_flag) {
return;
}
_abs_seqno = unwrap(header.seqno, _isn, _abs_seqno);
// 判断是否是 FIN 包
bool _fin_flag = false;
if (header.fin) {
_fin_flag = true;
}
uint64_t stream_index = _abs_seqno - 1 + header.syn;
_reassembler.push_substring(seg.payload().copy(), stream_index, _fin_flag);
}

optional<WrappingInt32> TCPReceiver::ackno() const {
// 判断是否是在 LISTEN 状态
if (!_syn_flag)
return std::nullopt;
// 如果不在 LISTEN 状态,则 ackno 还需要加上一个 SYN 标志的长度
uint64_t abs_ack_no = _reassembler.stream_out().bytes_written() + 1;
// 如果当前处于 FIN_RECV 状态,则还需要加上 FIN 标志长度
if (_reassembler.stream_out().input_ended()) {
++abs_ack_no;
}
return wrap(abs_ack_no, WrappingInt32(_isn));
}

size_t TCPReceiver::window_size() const { return _capacity - _reassembler.stream_out().buffer_size(); }

评论