0%

CS144-Lab0

本文基于指导文档进行编写。

CS144 的 Lab0 主要分为三部分

  • 第一部分是 VM 的安装/使用
  • 第二部分则是 telnet 等网络程序的尝试
  • 第三部分则是写一个基于 OS 自带 socket 库的网络程序和实现一个简单 ByteStream

第一部分可以略过。

第二部分则主要是介绍telnettelcat,其中telnet的作用就是建立 connection, 并用不同协议进行通信。 netcat则是用于建立 client/server 一类的 end-to-end 的端。

首先用

1
telcat 9091

建立一个对于 9091 端口的监听 socket, 然后打开另一个终端用

1
telnet localhost 9091

连接到该端口,此时 telcat 的窗口就会显示连接信息。

重点是第三部分的实验。这个实验将利用 Linux 的 Socket 构建一个基于 TCP 的程序,要求该程序可以连接到 Web Server,并抓取一个界面。

这里有些需要注意的要点:

  • 在 HTTP 协议中每行必须以‘’结尾
  • 不能漏了‘Connection: closed’, 不然进程会一直等待

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void get_URL( const string& host, const string& path )
{
TCPSocket sock1;
Address addr = Address( host, "http" );
sock1.connect( addr );
sock1.write( "GET " + path + " " + "HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n" );
while ( 1 ) {
string recv;
sock1.read( recv );
cout << recv;
if ( sock1.eof() )
break;
}
sock1.close();
}

在 ByteStream 部分,要实现对于数据的读写,笔者主要是基于std::queue实现的缓存, 主要难点在于 peek 函数,参考网上代码后,发现 string_view 必须像下列代码一样初始化:

1
2
3
4
string_view Reader::peek() const
{
return { &buffer.front(), 1 };
}

优化部分

用 string_view 和 move 实现移动语义:

两个队列存数据和引用

1
2
std::queue<std::string_view> buffer;
std::queue<std::string> buffer_actual;

Reader 的 pop 则要分类讨论:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void Reader::pop( uint64_t len )
{
bytesPopped += len;
for ( unsigned i = 0; i < len; ) {
if ( buffer.front().size() > len - i ) {
buffer.front() = buffer.front().substr( len - i );
i = len;
} else {
i += buffer.front().size();
buffer.pop();
buffer_actual.pop();
}
}

while ( !buffer.empty() && buffer.front().empty() )
buffer.pop();
bytesBuffered -= len;
}

最后优化的结果: img