cs144 lab0学习总结
障碍1:没有搞清楚ByteStream类,Writer类,Reader类各自的抽象职责,以及它们如何工作。这一点在webget那里也是一样的,半天都没搞明白webget用来干嘛的。
障碍2:类内成员变量设计非常混乱,经常因为犹豫一个变量是否有必要存在而反复的将该变量增删,然后又造成需要对相关代码进行修改,带来巨大的工作量。改进:1.给变量取一个清晰准确的名字。2.保持状态的最小化,理清楚哪些是必须存储的基础状态,哪些是不必要存储的派生状态(可以由基础状态计算),只存储基础状态,用一个函数接口来代替派生状态。3.选择合适的数据结构,思考类的核心操作是什么(增删查改,头部操作,还是尾部操作?),然后选择一个最合适的标准库容器。
障碍3:对于一些反复出现的重复代码,没有去设计对应的成员函数来简化代码,例如buffer_.size()函数,如果我设计一个接口getSize函数,那么我就不会因为障碍2中犹豫“到底是维护一个size_成员变量还是直接使用buffer_.size()”,然后在两者之间反复横跳而浪费那么多时间了。
障碍4:对于git,写代码的时候一次都没用过,下次争取用起来吧。
障碍5:不会直接在vscode上调试,最后还是直接粘贴到vs上调试的。。。目前也没啥头绪。
障碍6:英文水平有待提高,对于文件中的一些关键英文信息捕捉能力不足。。。
对于障碍1,再来理一下知识点吧。
webget:
TCP协议初步认知:TCP向应用层提供一个可靠的字节流 (reliable byte stream)。作为传输层协议,TCP不关心应用层(HTTP)报文的具体内容。它的任务只是将服务器发送的字节序列,不多不少、按顺序地传送到我们这里。TCP是“流式”的,这意味着我们不能指望一次 read() 就能读完整个HTTP响应,数据是像水一样从一端流到另一端的。我们必须在一个循环中,持续地从TCP的接收缓冲区中读取数据块(chunks/segments),直到连接的另一端关闭(由 sock.eof() 检测到)。
Connection: close:
本质:是HTTP协议的文本,它是一个应用层协议头部字段,是你发送的HTTP请求报文内容的一部分。
含义:“你好,Web服务器。我(客户端)发给你这个请求之后,不打算再用这条TCP连接发送任何新的HTTP请求了(即不使用持久连接)。
请你在处理完我的请求(此处即为GET指令)、发送完你的响应(将/hello网页内容发送到client)之后,主动关闭底层的TCP连接。”
shutdown函数(webget里面其实没用到):
本质:它是一个传输层的控制操作,直接作用于TCP连接的状态机。
含义:“你好,操作系统。对于这个TCP连接,我已经没有更多数据要发送了。请你立刻发送一个FIN(Finish)包给对方,告诉它我的发送数据流已经结束了。但是,请保持接收数据流开放,我还要等对方的回信。”
总结:webget中,Connection close是在相应处理后彻底关闭应用层和应用层之间的连接, 而shutdown是直接关闭应用层和应用层间一端向另一端发送数据的功能。这两者都是作用于传输层与传输层之间的TCP连接,而我们的read操作则是作用于传输层和应用层之间,这也符合网络分层的思想。
ByteStream类:
先讲一讲它实际的工作方式吧
ByteStream stream(2);
Writer& writer = stream.writer();
Reader& reader = stream.reader();
实际代码中并不会去分别创建一个writer类和一个reader类,对于writer和reader来说,它们都只是具有抽象意义上向字节流中写和从字节流中读的功能,实际上自身不存储任何字符串。虽然它们继承了ByteStream,但是那条字节流并不为它们所有。理论上来讲,把writer类和reader类设计为ByteStream的友元应该也没啥问题。这样的继承方式不是最常见的为了实现多态而继承,但不得不说,通过这种方式能够使writer类和reader类共用ByteStream中存储字符串的缓存区,进而使得writer类和reader类之间就好像真的有那么一条“可靠的字节流”的实时传输,实在让人惊叹。(但是AI说这种实现方式只是为了简化,其实好像不是主流啊)