2020/05/28 ~ 06/01
TCP协议的Lab告一段落,后面的是发送EthernetFrame和Router的lab
1. fsm是(finite state machine)的缩写,有限状态机
2. 重传列表的问题 , cpp的queue在空的时候也会返回一个默认值 , 需要判断空的情况 , 对语言的库不熟悉,排查了好久,之后都要当心为空返回默认值的情况 (虽然我觉得为空的时候peek front应该报错)
3. 主动关闭才需要linger , 被动关闭不需要 ,被动关闭的判断(inbound在outbound之前关闭)
4.每次tick timeout都需要重置, 但只有重传的时候才执行exponential backoff
5. 触发RST的场景
6.linger的判断
7.debug skill++ (ide断点, 还是没有打log好用)
由于"Two General's Problem' , clean shutdown是不可能实现的一个目标 , 但tcp使用了一个非常接近的实现 , 在送出最后一个ack之后等待10*rt_timeout,如果对端没有重传,则假设达成了clean shutdown
connection 和 receiver/sender对应的state
switch (state) {
case TCPState::State::LISTEN:
_receiver = TCPReceiverStateSummary::LISTEN;
_sender = TCPSenderStateSummary::CLOSED;
break;
case TCPState::State::SYN_RCVD:
_receiver = TCPReceiverStateSummary::SYN_RECV;
_sender = TCPSenderStateSummary::SYN_SENT;
break;
case TCPState::State::SYN_SENT:
_receiver = TCPReceiverStateSummary::LISTEN;
_sender = TCPSenderStateSummary::SYN_SENT;
break;
case TCPState::State::ESTABLISHED:
_receiver = TCPReceiverStateSummary::SYN_RECV;
_sender = TCPSenderStateSummary::SYN_ACKED;
break;
case TCPState::State::CLOSE_WAIT:
_receiver = TCPReceiverStateSummary::FIN_RECV;
_sender = TCPSenderStateSummary::SYN_ACKED;
_linger_after_streams_finish = false;
break;
case TCPState::State::LAST_ACK:
_receiver = TCPReceiverStateSummary::FIN_RECV;
_sender = TCPSenderStateSummary::FIN_SENT;
_linger_after_streams_finish = false;
break;
case TCPState::State::CLOSING:
_receiver = TCPReceiverStateSummary::FIN_RECV;
_sender = TCPSenderStateSummary::FIN_SENT;
break;
case TCPState::State::FIN_WAIT_1:
_receiver = TCPReceiverStateSummary::SYN_RECV;
_sender = TCPSenderStateSummary::FIN_SENT;
break;
case TCPState::State::FIN_WAIT_2:
_receiver = TCPReceiverStateSummary::SYN_RECV;
_sender = TCPSenderStateSummary::FIN_ACKED;
break;
case TCPState::State::TIME_WAIT:
_receiver = TCPReceiverStateSummary::FIN_RECV;
_sender = TCPSenderStateSummary::FIN_ACKED;
break;
case TCPState::State::RESET:
_receiver = TCPReceiverStateSummary::ERROR;
_sender = TCPSenderStateSummary::ERROR;
_linger_after_streams_finish = false;
_active = false;
break;
case TCPState::State::CLOSED:
_receiver = TCPReceiverStateSummary::FIN_RECV;
_sender = TCPSenderStateSummary::FIN_ACKED;
_linger_after_streams_finish = false;
_active = false;
break;
}
2020/05/24 ~ 05/27
1.超时机制是 exponential backoff , 指数补偿
2.下一个 lab 还是多写点 helper 吧
3.fin 也占一个窗口位
4.只要收到 ack 就要更新窗口
5.cpp 的 list 遍历,erase 后返回下一个 iterator 的指针
6.segfault 要怎么调试?
7.前闭后开区间的意义: unsigned int 不能为负值,前闭后开可以定义大小为 0 的区间
8.初始 windowSize 为 1 (发 syn)
2020/05/20 ~ 05/23
1.实现对 syn,fin,和带data 的 tcp segment 的接收,处理和响应
2.看着 test case 写了第一版 pesudo code, 然后直接在 pesudo code 上重构了一版,以窗口为模型,截取在窗口内的字节流
3.最后精简完,就 100 多行代码...用了 2 天
4.测试用例很完善, 真的感谢课程作者
5.lab2 对 lab1的 reassembler 增加了容量限制的 test case , 又回去 debug 了一会 , 涉及容量的问题只取在窗口内的字节就行了
6.同时收到 fin 和数据的时候,要处理完数据再处理 fin
7.window size只更新连续字节流部分
8.还没找到这套测试框架打印数据的方法
9.写入 Reassembler 的时候要用absolute index, 从 0 开始的,不计算 syn 位的索引
2020/05/18 ~ 05/20
1.lab1用了5,6个小时的时间才做完,测试用例有点难度
2.实现的是`TCP`的一个组件,重新组装segment成为连续的字节流,提供给上层应用
3.本来想使用递归让代码看起来清楚一点,结果`segfault`了,还是改成循环了
4.在虚拟机里写的代码,没有输入法,写的英文注释看起来挺美观,蹩脚的英文
5.没有人肉走完`test case`就开始写代码,结果是想的模型不对,不能满足后面的`case`,基本是推翻重写 (第一次是用`segment`,字符串的角度进行重组,但遇到了增量更新,未重组字节级别的覆盖,重组字节级别覆盖的`case`,最后把思考的模型改成字节流,代码也清晰许多),这点让我想到业务开发里也是一样,没有往后思考可能的需求(更完善的`test case` ) ,导致代码只能东拼西凑满足功能,完全不堪入目。
7.pesudo code + test case is a powerful combo
8.maybe multiple eof , try store every eof state
9 implemented an out of order , repeat, overlapping , increment update , reliable reassembler
2020/05/17 ~ 05/18
0.lab0第一个任务是一个简单的网页内容获取程序 , 直接调用 Linux 的 TCP 协议栈接口 ,会在之后完成 lab4 时,使用自己写的 TCP 协议替换系统实现
1.第二个任务实现了一个in-memory reliable ordered bystream,做这个的目的是因为tcp实际上就是这样的一个可靠有序的字节流,不过是基于网络的,
实现这一个小lab可以更好地理解了tcp两端的一些交互 . 实际上是一个字节流的队列 , 和 Java 里的 stream 设计类似, 一端 writer 写入,
一端 reader 读出,写入一端有关闭操作 , 重点还是要理解 eof 的判断
比如说http的请求中,客户端发送完请求后会向服务端发送一个SHUTDOWN_WRITE的 信号, 就对应byteSteam类的input_ended(),
这时候服务端就知道,在这个sequence number之后没有新数据了,接收完前面的字节就可以开始处理请求, 这里的seq number就可以用作eof的判断
2.`webget`这个`task`用课程提供的虚拟镜像运行不了,折腾了好久,放到自己的`ubuntu16.04`里成功运行,越底层的语言开发环境越折磨人