update write up
This commit is contained in:
parent
d76022f9d1
commit
cb32c293c8
@ -19,8 +19,7 @@ void TCPReceiver::segment_received(const TCPSegment &seg) {
|
||||
}
|
||||
if (!_syn)
|
||||
return; // abandon packets before SYN
|
||||
uint64_t checkpoint = stream_out().bytes_written() ? stream_out().bytes_written() - 1 : 0;
|
||||
// special case for initial SYN
|
||||
uint64_t checkpoint = stream_out().bytes_written();
|
||||
uint64_t abs_seqno = unwrap(seg.header().seqno, _isn, checkpoint);
|
||||
// In your TCP implementation, you’ll use the index of the last reassembled byte as the checkpoint.
|
||||
// So, the bytes_written-1 (Stream Indices) should be this value
|
||||
@ -30,7 +29,7 @@ void TCPReceiver::segment_received(const TCPSegment &seg) {
|
||||
// assertion: when abs_seqno is 0, this packet must be syn
|
||||
uint64_t index = abs_seqno - (abs_seqno ? 1 : 0); // special case for SYN&FIN
|
||||
_reassembler.push_substring(seg.payload().copy(), index, seg.header().fin);
|
||||
_abs_ackno = stream_out().bytes_written() + 1 + (stream_out().input_ended() ? 1 : 0);
|
||||
auto _abs_ackno = stream_out().bytes_written() + 1 + (stream_out().input_ended() ? 1 : 0);
|
||||
_ackno = wrap(_abs_ackno, _isn);
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@ class TCPReceiver {
|
||||
size_t _capacity;
|
||||
WrappingInt32 _isn{0};
|
||||
WrappingInt32 _ackno{0};
|
||||
uint64_t _abs_ackno{0};
|
||||
bool _syn{};
|
||||
|
||||
public:
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
Lab 0 Writeup
|
||||
=============
|
||||
|
||||
My name: [Catfood]
|
||||
My name: Catfood
|
||||
|
||||
My SUNet ID: [998244353]
|
||||
My SUNet ID: 998244353
|
||||
|
||||
I collaborated with: [An orange cat]
|
||||
I collaborated with: An orange cat
|
||||
|
||||
This lab took me about [2] hours to do. I [did not] attend the lab session.
|
||||
This lab took me about `2` hours to do.
|
||||
|
||||
My secret code from section 2.1 was: [294080]
|
||||
My secret code from section 2.1 was: `294080`
|
||||
|
||||
- Optional: I had unexpected difficulty with: [describe]
|
||||
- Optional: I had unexpected difficulty with: [打字的手速太慢,telnet会超时]
|
||||
|
||||
- Optional: I think you could make this lab better by: [describe]
|
||||
|
||||
@ -19,6 +19,9 @@ My secret code from section 2.1 was: [294080]
|
||||
|
||||
- Optional: I'm not sure about: [describe]
|
||||
|
||||
实现细节描述
|
||||
============
|
||||
|
||||
2.1.2:
|
||||
```
|
||||
➜ sponge git:(lab0-startercode) ✗ telnet cs144.keithw.org http
|
||||
@ -68,9 +71,10 @@ Connection closed by foreign host.
|
||||
```
|
||||
|
||||
2.2:
|
||||
|
||||
学校的邮件系统比较智障,做不了
|
||||
|
||||
2.3
|
||||
2.3:
|
||||
```
|
||||
➜ sponge git:(lab0-startercode) ✗ telnet localhost 9090
|
||||
Trying 127.0.0.1...
|
||||
@ -87,3 +91,20 @@ fuck
|
||||
lalal
|
||||
```
|
||||
|
||||
3.4:
|
||||
|
||||
他的提示没啥用,但是doxygen里面有个例子,可以直接看那个例子。
|
||||
地址可以直接放域名,`Address(host, protocol)`这个重载是可以DNS查询的,因此直接用就行,然后TCP socket,`connect->write->loop read`就好了。
|
||||
|
||||
4:
|
||||
|
||||
Buffer开了一个STL的`deque`,感觉是最适合做这种buffer的容器了,能够前后插入删除、常数级随机访问、动态调整空间,非常棒的性质。数据类型用的是`char`(byte),方便调整。
|
||||
|
||||
write接口没啥东西,控制一下不要超出空间就行。
|
||||
read接口比较智障,需要这样一个组合,但是实际上好像测试的时候都没用到。。。
|
||||
```cpp
|
||||
std::string data_read = peek_output(len);
|
||||
pop_output(len);
|
||||
return data_read;
|
||||
```
|
||||
最智障的是它的`peek_output`和`pop_output`这两个的设计:peek只能读,啥也不能动,因为是个const函数;pop需要再把东西删掉,然后`read`就是他们的组合。需要注意一下,更新`bytes_read`是在pop里面而不是read,因为大概率在上层的实现中,可能需要把直接调用peek和pop而不是read。
|
||||
@ -1,24 +1,37 @@
|
||||
Lab 1 Writeup
|
||||
=============
|
||||
|
||||
My name: [your name here]
|
||||
My name: Catfood
|
||||
|
||||
My SUNet ID: [your sunetid here]
|
||||
My SUNet ID: 998244353
|
||||
|
||||
I collaborated with: [list sunetids here]
|
||||
I collaborated with: An orange cat
|
||||
|
||||
I would like to thank/reward these classmates for their help: [list sunetids here]
|
||||
|
||||
This lab took me about [n] hours to do. I [did/did not] attend the lab session.
|
||||
This lab took me about `3` hours to do.
|
||||
|
||||
Program Structure and Design of the StreamReassembler:
|
||||
[]
|
||||
|
||||
首先写几个 dis-ambiguity
|
||||
1. capacity限制:容量限制指的是bytestream.size + aux_storage.size。比较具有迷惑性的是auxiliary storage的容量,这里需要把中间空的字节也算进去,因此就可以简单地计算为`first_unacceptable = first_unread + capacity = first_unassembled + aux_buffer.size()`。形象地理解为类似于一个大的空白数组,往里面填东西,填满了开头的连续部分就push到bytestream里面。
|
||||
2. 关于丢弃:这里是以字节为单位的丢弃,而不是以packet为单位,也就是一个string进来,有一部分超出了容量限制,这时候不能直接返回不写入,而是要把不超出限制的部分写进入,剩下的丢掉。
|
||||
3. `unassembed_bytes`的计算:这个统计的就是实际收到的但是还没push到字节流的字节,不包括空白。因此需要在接受的时候动态统计。
|
||||
4. `EOF`处理:因为可能带EOF的packet先到达,前面还有没收到的部分,因此需要单独记住EOF对应的Index,等push到这个Index的时候,再去调用字节流的`end_input()`。
|
||||
|
||||
然后简单说一下实现:
|
||||
- 数据结构是两个`deque`,一个用来当缓冲区,另一个用来标志是否是收到的字节(这样就不用实现复杂的区间合并了,虽然需要消耗双倍内存)。开头的时候需要重新调整大小,因为可能被read过了。
|
||||
- 过程中需要注意各种状态的取值,不要超过容量,也不要出现非法操作(比如取空队列的front,这个好像是个UB)
|
||||
- 每次收到数据之后,都处理一下是否能够推进字节流,说明上是这么要求的(“尽快”)
|
||||
|
||||
最后简单记一下STL中`deque`的一些用法:
|
||||
- 初始化:可以用`(size, data)`这样的方式一次性指定初始容量
|
||||
- 入队出队:这个容器可以`push/pop_front/back`
|
||||
- 调整大小:`resize(newsize, data)`,这个调用的行为符合直觉,data是用来填充的(如果增加了大小);如果减小了大小,那么尾部数据会被扔掉
|
||||
===
|
||||
Implementation Challenges:
|
||||
[]
|
||||
[主要时间都浪费在了调试各种corner case上面了,感觉要是自己测试根本测不出来,感谢写测试的staff,太强啦]
|
||||
|
||||
Remaining Bugs:
|
||||
[]
|
||||
无
|
||||
|
||||
- Optional: I had unexpected difficulty with: [describe]
|
||||
|
||||
@ -26,4 +39,4 @@ Remaining Bugs:
|
||||
|
||||
- Optional: I was surprised by: [describe]
|
||||
|
||||
- Optional: I'm not sure about: [describe]
|
||||
- Optional: I'm not sure about: [万一,eof的地方冲突了咋办?虽然好像可以直接忽略来着]
|
||||
@ -1,24 +1,36 @@
|
||||
Lab 2 Writeup
|
||||
=============
|
||||
|
||||
My name: [your name here]
|
||||
My name: Catfood
|
||||
|
||||
My SUNet ID: [your sunetid here]
|
||||
My SUNet ID: 998244353
|
||||
|
||||
I collaborated with: [list sunetids here]
|
||||
I collaborated with: An orange cat
|
||||
|
||||
I would like to thank/reward these classmates for their help: [list sunetids here]
|
||||
|
||||
This lab took me about [n] hours to do. I [did/did not] attend the lab session.
|
||||
This lab took me about `3.5` hours to do.
|
||||
|
||||
Program Structure and Design of the TCPReceiver and wrap/unwrap routines:
|
||||
[]
|
||||
|
||||
**wrap/unwrap**
|
||||
|
||||
这个部分有点迷惑,主要是一不小心就溢出了,然后就挂了。写的时候需要注意减法会不会出现小的-大的,因为这里是无符号操作,直接就下溢了。尤其是在比较大小的时候。
|
||||
这东西我感觉有比较好的位运算解法,但是我懒得思考了。
|
||||
|
||||
**TCP Receiver**
|
||||
|
||||
这部分代码其实不多,主要是把流程整明白,以及调试各种 corner case 的过程。
|
||||
- 首先判断SYN,因为这个没办法通过字节流状态来判断是否已经连上了,因此需要一个变量来记录状态。如果没有syn,就直接返回了。发现syn之后,更新一下起始序列号。
|
||||
- 然后是转换成绝对序号,因为要求用最后一个写入字节的序号作为checkpoint,因此直接用`bytes_written`就可以了(正好对应字节的绝对序号(=流序号+1))。
|
||||
- 接下来是一个 corner case,如果一个字节的序号和SYN相同,需要抛弃。因此检测绝对序号为0的时候,这个数据包是不是SYN。
|
||||
- 然后写入到 reassembler 里面,index 需要转换一下。因为要考虑到 SYN+FIN 同时的情况,因此还是选择了写一个空packet到里面,然后放上 fin 的方法,这样代码会少一点。
|
||||
- 最后更新 `ackno`,这里需要用到 `first unassembled = bytes_written + SYN + FIN`,再wrap一下就好了。
|
||||
- 其他函数的实现符合直觉,直接写就行。
|
||||
|
||||
Implementation Challenges:
|
||||
[]
|
||||
[special case 太坑了]
|
||||
|
||||
Remaining Bugs:
|
||||
[]
|
||||
[大概没有吧(悲)]
|
||||
|
||||
- Optional: I had unexpected difficulty with: [describe]
|
||||
|
||||
@ -26,4 +38,4 @@ Remaining Bugs:
|
||||
|
||||
- Optional: I was surprised by: [describe]
|
||||
|
||||
- Optional: I'm not sure about: [describe]
|
||||
- Optional: I'm not sure about: [在注释里面给出了关于unwrap的时候,一种特殊情况的思考]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user