Program Structure and Design

3.4 geturl

这个实验非常简单,只需要读懂他这里的API就可以做了,其中从socket里面读数据的方式和pipe是完全一致的,都用read来读,write来写。

首先使用

1
Address address { host, "http" };

来创建一个地址

然后用

1
2
3
4
TCPSocket socket;
socket.connect( address );
socket.write( "GET " + path + " HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n" );
string response;

来创建socket,接下来不断读就行了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string response;
bool is_line_one = true;
while ( !socket.eof() && !socket.closed() ) {
string tmp;
socket.read( tmp );
if ( is_line_one ) {
if ( tmp.starts_with( "HTTP/1.1 200 OK" ) ) {
is_line_one = false;
} else {
throw runtime_error( "HTTP request failed" );
}
}
if ( !tmp.starts_with( "Content-type: " ) ) {
response += tmp;
}
}
socket.close();

这里我处理了一下如果最开始HTTP的状态码不是200的情况

3.5 byte_stream

这个部分主要就是在内存里面模拟实现一个buffer,这里我采用的是用两个 std::deque 来存,一个存原始的string副本(用来创建string_view,不然直接用传入参数创建会导致栈被回收时,提供的指针未定义)另一个存string_view来做切片。

具体实现其实很简单,只要每次push的时候,更新对应的计数器,保存string副本,然后按照可用大小创建string_view切片就行了,但是实际上由于string_view的特性我被坑惨了,具体下一部分讲。

Implementation Challenges

本次实验我遇到的最抽象的bug就是string_view的构造函数,他有两个原型,第一个是

1
constexpr basic_string_viewconst CharT* s );

另一个是

1
constexpr basic_string_viewconst CharT* s, size_type count );

在cppreference的string_view界面里面,没有告诉我,第一个构造函数会默认以第一个\0作为字符串的结束,我以为他的原型是

1
constexpr basic_string_viewconst string& str );

导致一旦传入的流里面包括了 \0 就会出错,而前面的测试用例太弱了,导致前几个可以模拟的没有出这个错,后面随机几百次的时候才遇到。

解决方案——防御性编程

后续我是使用断言和异常来调试出这个问题的,即添加了判断

1
2
3
4
5
6
7
8
if ( data.size() != base_view.size() ) {
throw length_error( "Error: string_view size is not equal to data size in line "
+ to_string( __LINE__ )
+ "the data size is: "
+ to_string( data.size() )
+ " the string view size is: "
+ to_string( base_view.size() ) );
}

最终让我看出来到底问题在哪里了

Experimental results and performance.

2.1拉取网页

这里使用给出的命令可以拉取对应的网页,但是由于示例里面的 http://cs144.keithw.org/hello 老是408 超时,所以我选择拉取我的博客的主页,下面是截图

补后续:
后面又拉取成功了

2.1发邮件

遇到的第一个问题是,在本地用命令

1
base64 file

进行base64编码的时候,输出不知道为什么少了一个=导致根本登不上去

2.2监听网络

利用这个可以发现,在任意一边按回车另一边都会对应显示

3.4 geturl

3.5 byte_stream


这里的速度达到了 达到了要求