我使用的是 Windows + VirtualBox + centos7 + vscode + gcc8
如果能在Linux下直接调试再好不过,无Linux环境的兄弟可以参考的我的配置
https://gitee.com/HappyBinbin/my-notes/blob/master/%E6%95%88%E7%8E%87%E5%B7%A5%E5%85%B7/vscode%E5%81%9Assh%E8%BF%9C%E7%A8%8B%E7%BB%88%E7%AB%AF.md
https://www.cnblogs.com/jixiaohua/p/11732225.html
https://stackoverflow.com/questions/64101326/field-ifru-addr-has-incomplete-type-sockaddr
抓取Web网页,这个很容易,跟着步骤来就行。
注意事项
通过 smtp 来发送 eaml,我们没有环境连接到 stanford的邮件服务器,可以用国内的邮件服务器,例如qq邮箱。去qq邮箱打开 smtp服务,获取授权码。
然后根据步骤
剩下的按照步骤来即可成功
这个我懒得装 netcat了,就不搞了
利用 Linxu 提供的 socket 编写一个网络程序,抓取网页。
参考 -> 1、搭建环境
提醒我们使用c11的一些注意事项
让我们去看 Sponge 文档
正式开始编码
根据lab的提示开始构思:
void get_URL(const string &host, const string &path) {
// Your code here.
// 创建TCPSocket 套接字
TCPSocket socket;
// 将Address 绑定到套接字并连接 connetct,端口为 http 端口
socket.connect(Address(host,"http"));
// 发送 GET 请求,按照HTTP GET 请求的格式
string info = "GET " + path + " HTTP/1.1\r\n" +
"HOST: " + host + "\r\n" +
"Connetction: close\r\n\r\n";
socket.write(info);
// 发送完毕之后,关闭发送端
socket.shutdown(SHUT_WR);
// 服务器接收到 SHUTDOWN请求后,将剩余的数据发送完后,结尾会附带一个EOF,表示结束
while(!socket.eof()){
cout << socket.read() << endl;
}
socket.close();
return;
}
这部分要求我们实验一个在内存中的可靠字节流传输
了解要求,其实就是写一个类似管道的东西,一边写入,一边输出。
编写者的界面如下所示:
// Write a string of bytes into the stream. Write as many
// as will fit, and return the number of bytes written.
size_t write(const std::string &data);
// Returns the number of additional bytes that the stream has space for
size_t remaining_capacity() const;
// Signal that the byte stream has reached its ending
void end_input();
// Indicate that the stream suffered an error
void set_error();
这是读者的界面:
// Peek at next "len" bytes of the stream
std::string peek_output(const size_t len) const;
// Remove ``len'' bytes from the buffer
void pop_output(const size_t len);
// Read (i.e., copy and then pop) the next "len" bytes of the stream
std::string read(const size_t len);
bool input_ended() const; // `true` if the stream input has ended
bool eof() const; // `true` if the output has reached the ending
bool error() const; // `true` if the stream has suffered an error
size_t buffer_size() const; // the maximum amount that can currently be peeked/read
bool buffer_empty() const; // `true` if the buffer is empty
size_t bytes_written() const; // Total number of bytes written
size_t bytes_read() const; // Total number of bytes popped
请打开libsponge / byte stream.hh和libsponge / byte http://stream.cc文件,并实现提供此接口的对象。 在开发字节流实现时,可以使用make check lab0运行自动化测试。
虽然string的各种方法一般被认为会比普通数组的操作要慢,但字符串的拼接是一个例外,string的+拼接的确要比按索引值逐个复制要快。
确定好数据结构之后,就比较简单了。
注意:
这个函数不知道啥意思,我删了,void DUMMY_CODE(Targs &&… /* unused */) {}
class ByteStream
{
private:
// Your code here -- add private members as necessary.
std::deque _buffer = {};
size_t _capacity = 0;
size_t _read_count = 0;
size_t _write_count = 0;
bool _input_ended_flag = false;
// Hint: This doesn't need to be a sophisticated data structure at
// all, but if any of your tests are taking longer than a second,
// that's a sign that you probably want to keep exploring
// different approaches.
bool _error = false; //!< Flag indicating that the stream suffered an error.
}
ByteStream::ByteStream(const size_t capacity)
{
_capacity = capacity;
;
}
size_t ByteStream::write(const string &data)
{
// 获取data的长度
size_t len = data.length();
// 判断缓冲区的容量大小,限制写入大小,防止溢出
if (len > _capacity - _buffer.size())
{
len = _capacity - _buffer.size();
}
// 记录写入的字节数
_write_count += len;
// 往缓冲区中写入数据
for (size_t i = 0; i < len; i++)
{
_buffer.push_back(data[i]);
}
return len;
}
//! \param[in] len bytes will be copied from the output side of the buffer
string ByteStream::peek_output(const size_t len) const
{
size_t length = len;
if (length > _buffer.size())
{
length = _buffer.size();
}
return string().assign(_buffer.begin(), _buffer.begin() + length);
}
//! \param[in] len bytes will be removed from the output side of the buffer
void ByteStream::pop_output(const size_t len)
{
size_t length = len;
if (length > _buffer.size())
{
length = _buffer.size();
}
_read_count += length;
while (length--)
{
_buffer.pop_front();
}
}
//! Read (i.e., copy and then pop) the next "len" bytes of the stream
//! \param[in] len bytes will be popped and returned
//! \returns a string
std::string ByteStream::read(const size_t len)
{
size_t byte_read = (len > _buffer.size()) ? _buffer.size() : len;
string ret = peek_output(byte_read);
pop_output(byte_read);
return ret;
}
void ByteStream::end_input()
{
_input_ended_flag = true;
}
bool ByteStream::input_ended() const
{
return _input_ended_flag;
}
size_t ByteStream::buffer_size() const
{
return _buffer.size();
}
bool ByteStream::buffer_empty() const
{
return _buffer.size() == 0;
}
bool ByteStream::eof() const
{
return buffer_empty() && input_ended();
;
}
size_t ByteStream::bytes_written() const
{
return _write_count;
}
size_t ByteStream::bytes_read() const
{
return _read_count;
}
size_t ByteStream::remaining_capacity() const
{
return _capacity - _buffer.size();
}