Stanford CS144 lab4
-
总览
- 一个TCP endpoint(TCPConnection)是TCPSender与TCPReceiver的结合体
- TCPConnection的segment可以被放入UDP的数据包中或则IP的数据包中
- 这个lab最后会基于实现的TCPConnection,给出一个叫做CS144TCPSCocket类,并基于此修改之前写的webget
-
TCPConnection的接收发送策略
- 接受方
- 如果接受到的报文
RST
置位,此时需要切断连接,把出入端(in/outbound)设置到错误状态 TCPReceiver
检查收到的报文段这些字段:seqno
,SYN
,payload
,FIN
- 如果接受到的报文中
ACK
置位(一般建立连接后,都是启用状态),那么接受方需要查看ackno
与window_size
字段 - 如果传来的报文占据了序列号,那么
TCPConnection
需要确保至少有一个回应报文,并且其中设置好了正确的ackno
和window size
- 这一段表示需要用到之前的写好的
send_empty_segment()
- 如果接受到的报文
- 发送方
- 对于发送出(outgoing)的报文,需要设置好相关字段
- 发送报文时,一并发送确认,设置好
ackno
与window_size
,并置位ACK
,这应该是捎带确认(piggybacking)
- 时间处理
TCPConnection
需要告诉调用tick
函数的TCPSender
距离上一次调用经过的时间- 当
consecutive retransmissions
超过一个阈值TCPConfig::MAX RETX ATTEMPTS
,终止连接,发送一个置位RST
报文 - ?
- 接受方
-
TCP connection的结束, 涉及到一致性问题
- 有两种连接结束的方式,第一种是
unclean shutdown
,也就发送或者接受置位了RST
的报文,这种情况下in/outbound
的ByteStream
都应该被置为error状态,且active()
立即返回false - 第二种是
clean shutdown
,由于两军问题Two Generals Problem
, TCP并不能完全实现一个clean shudown
- 对于一个
clean shutdown
有四个先置条件,1
inbound字节流完全被push并被重组,2
outbound字节流被完全出去了,也就是说fin包被发送出去了,3
outbound字节已经被遥远的对等实体完全确认了,4
本地的对等实体自信的认为遥远的对等实体满足条件3 - 另外关闭时有两种情况,一种是主动关闭,一种时被动关闭,当然这里的关闭
close
是对于一端来说的,关闭后自己就可以不发数据了,主动关闭
,需要lingering
2MSL(lab里是10 × cfg.rt timeout),,而被动关闭不需要,这里作为附加题,
我认为是由于对方先把FIN包发送给过来了,并且作为被动关闭者只要接收到了对方的对于自己的FIN包的ack就能确保关闭
但是这段话意味着什么,
应该是指对方过早的发送完字节流并且完全被上方应用接受了,那么就完全不需要对方的重传了,这时候就不需要lingering,但是这能够确保对方收到了己方对于对方FIN的ack吗?
- 对于一个
- 有两种连接结束的方式,第一种是
-
实现
- 对于
segment_received
函数,- 涉及到
_sender
的ack确认与窗口的修改,也就输是TCPSender::ack_received
,修改完对方窗口的大小,_sender
需要相应的发送数据; - 另外还需要
_receiver
把数据上传到inbound stream
,也就是调用TCPReceiver::segment_received
- 涉及到
- 对于
-
实现中遇到的问题
-
面向测试编程,由于测试用例过多(162个),把输出重定向到
lab4.log
中 -
对于置位
RST
报文的发送,如果_sender中_segement_out容量为空,那么需要添加一个empty segment
-
kills the connection permanently
是指发送rst -
-
这个测试用例是双方
同时打开,也就是双方都作为主动发起方,并且这里与《TCP/IP 详解》中描述的不一致,这中情况下,对于第二次握手可以不需要置位SYN了
-
关于如何测试单个用例
-
注意需要删除打印语句
-
吞吐量测试没过,开始排查
lab1中用了
unorered_map
,太慢,很多人都用set对于
std::__detail::_Map_base
,减少map索引查找的时间,unordered_map
由于是链表存储,最坏的取可以到达O(n) -
使用
scp
命令将本地wsl2项目传递到云服务器上
-
在ubutun上无法用自己的TCP/IP实现通信,
-
好吧┭┮﹏┭┮没办法,
lab1 stream_reassembler
只能够用set
重写了 -
另外更好的优化是在
lab0
中用BufferList
来当作ByteStream
的容器,把 ByteStream 类中字节流的容器由 Lab0 最初的 std::list_stream{}; 改为 BufferList _stream{},具体的优化 profile
,参见这里 -
几张比较有用的图
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通