目录
3 Writing a network program using an OS stream socket
4 An in-memory reliable byte stream
1 实验环境
官方文档提供了三种支持运行该 Lab 的选择,我选择了VMware和Ubuntu18.04。下载,安装,配置共享文件夹不再赘述。
2 Networking by hand
这部分内容比较简单,跟着文章步骤即可。2.1手工获取一个网页;2.2 手工发送电子邮件;2.3 完成一个双工通信。
2.1 Fetch a Web page
1.通过浏览器访问网站 http://cs144.keithw.org/hello,可以看到以下信息:
2. 在ubuntu终端,手动访问页面并观察结果
命令输入的时候要快一些,不然会Timeout,如下:
3. 访问网站 http://cs144.keithw.org/lab0/sunetid ,返回一个密码。这里编的sunetid 2022。
2.2 Send yourself an email
这部分的实验内容是用终端登上QQ邮箱服务器(官方文档用的是斯坦福校内服务器),向另一个邮箱发一封邮件。
登陆QQ邮箱服务器需要输入邮箱的 base64 编码( xxxxxx@qq.com 的base64编码) 输入开启 IMAP/SMPT 时授权码的 base64 编码(授权码无空格)
转码工具:https://www.qqxiuzi.cn/bianma/base64.htm
邮箱授权码获取步骤:https://blog.csdn.net/lzh1415926/article/details/122241446
实验结果:
2.3 Listening and connecting
这部分的实验内容是两个终端可以相互通信,在终端1输入信息,终端2会显示,反之亦然。
3 Writing a network program using an OS stream socket
从这一部分开始需要编写c++代码。需要先配置一下IDE,本试验使用了VScode,安装教程如下:
基于Ubuntu的VScode下载安装教程_纯粹.的博客-CSDN博客_ubuntu下载vscode
3.1 按步骤先构建程序,暂不赘述。
3.2- 3.3 是讲述实验基础的一些内容,浅看一下即可。
3.4 webget.cc是为了使用Sponge中提供的基础类完成一个简单HTTP请求的发送并将返回的请求打印出来。(可以理解为用编程来实现2.1.2的内容)。实验过程如下:
1) 首先进入sponge文件夹,输入code . 会自动打开VScode编译器。
2) 在/apps/webget.cc 下,完成get_URL函数。
具体代码及注释如下:
void get_URL(const string &host, const string &path) {
Address address(host, "http"); //传入主机的host 和需要的服务
TCPSocket socket; //创建一个socket对象
socket.connect(address); // socket对象和服务器连接
// 利用字符串拼接,参考2.1.2构建一个http请求报文
socket.write("GET " + path + " HTTP/1.1\r\n"); // \r\n 表示回车
socket.write("HOST: " + host + "\r\n");
socket.write("\r\n");
socket.shutdown(SHUT_WR); // request结束
// content
while (!socket.eof()) { //如果管道没有关,持续读输入进来的数据
std::cout << socket.read(1);
}
socket.close(); // 关闭socket
}
3) 再次访问网站,得到回复Hello, CS144!
4) 用其他网站案例测试一下:
100%通过,实验完成。
4 An in-memory reliable byte stream
这部分实验内容是写一个在内存中的可靠字节流。就是类似于读/写缓冲器的东西,提供了接口形式去实现就行了。这里使用了 deque
双向队列。双向队列支持头尾读写,刚好对应字节流从尾部写入从头部读取的特性,并且拥有迭代器,完美支持了该字节流类中的 peek 操作。
需要编写代码的两个文件分别为:
.h 文件:
#ifndef SPONGE_LIBSPONGE_BYTE_STREAM_HH
#define SPONGE_LIBSPONGE_BYTE_STREAM_HH
#include <string>
#include <deque>
//! \brief An in-order byte stream.
class ByteStream {
private:
size_t max_capacity = 0; //缓冲区最大容量
size_t _bytes_written = 0; //输入端写入的长度
size_t _bytes_read = 0; // 输出端读取的长度
std :: deque<char> _buf{}; //缓冲区队列
bool is_end = false;
bool _error = false; //!< Flag indicating that the stream suffered an error.
public:
后边不需要改,所以略去
.c 文件
#include "byte_stream.hh"
template <typename... Targs>
void DUMMY_CODE(Targs &&... /* unused */) {}
using namespace std;
//初始化字节流数据,设置缓冲区的最大容量
ByteStream::ByteStream(const size_t capacity) {
max_capacity = capacity;
}
// 输入端写数据,存入到缓冲队列中
size_t ByteStream::write(const string &data) {
// 如果队列满了 返回 0;
if(remaining_capacity() == 0) return 0;
size_t write_size = (data.size() <= remaining_capacity()) ? data.size() : remaining_capacity();
for(size_t i = 0; i < write_size; i ++)
{
_buf.push_back(data[i]);
}
_bytes_written += write_size;
return write_size;
}
//! \param[in] len bytes will be copied from the output side of the buffer
// 查看缓冲区的队列内容,但是不出列
string ByteStream::peek_output(const size_t len) const {
// DUMMY_CODE(len);
// return {};
size_t buf_size = (len <= buffer_size()) ? len : buffer_size();
string data;
data.assign(_buf.begin(), _buf.begin() + buf_size);
return data;
}
//! \param[in] len bytes will be removed from the output side of the buffer
// 出队列,从缓冲区删除len长度的数据
void ByteStream::pop_output(const size_t len) {
// DUMMY_CODE(len);
size_t buf_size = (len <= buffer_size()) ? len : buffer_size();
for(size_t i = 0; i < buf_size; i ++)
{
_buf.pop_front();
}
_bytes_read += buf_size;
}
//从缓冲区读出长度为len的数据
std::string ByteStream::read(const size_t len) {
string buf_read = peek_output(len);
pop_output(len);
return buf_read;
}
void ByteStream::end_input() { is_end = true; }
bool ByteStream::input_ended() const { return is_end; }
size_t ByteStream::buffer_size() const { return _buf.size(); }
bool ByteStream::buffer_empty() const { return _buf.empty(); }
bool ByteStream::eof() const { return buffer_empty() && is_end; }
size_t ByteStream::bytes_written() const { return _bytes_written; }
size_t ByteStream::bytes_read() const { return _bytes_read; }
size_t ByteStream::remaining_capacity() const { return max_capacity - _buf.size(); }
实验结果:
100%通过,实验完成。
Ubuntu总是断网怎么重连: