CS144 lab0: warmup
Lab 0: networking warmup
1. 环境
依赖配置
sudo apt update && sudo apt install git cmake gdb build-essential clang \clang-tidy clang-format gcc-doc pkg-config glibc-doc tcpdump tshark
g+±13配置
- ppa中科大源
# deb https://ppa.launchpadcontent.net/ubuntu-toolchain-r/test/ubuntu/ jammy main
deb https://launchpad.proxy.ustclug.org/ubuntu-toolchain-r/test/ubuntu/ jammy main
# deb-src https://ppa.launchpadcontent.net/ubuntu-toolchain-r/test/ubuntu/ jammy main
- 安装
g++-13 gcc-13
sudo apt install gcc-13
sudo apt install g++-13
- 设定优先级
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 11
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 11
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
- 版本检查
g++ -v
gcc -v
- cmake版本安装
git clone https://gitee.com/mirrors/CMakesource.git
./configure
make && make install
更新apt源
sudo update-alternatives --install /usr/bin/cmake cmake /usr/local/bin/cmake 1 --force
2. 使用命令获取网页
2.1 http获取网页
telnet到服务器上
telnet cs144.keithw.org http
输入http方法,指定主机,输入完成后还需要按一次enter
GET /hello HTTP/1.1 \n
Host: cs144.keithw.ort \n
\n
输入成功后可以得到
Hello, CS144!
的字样。
2.2 smtp输入邮箱
没有内网权限,跳过这个实验
2.3 本地服务器
在本地使用 netcat
命令
- 服务端
netcat -v -l -p 9090
- 客户端
telnet localhost 9090
之后分别在客户端和服务端输入,两方都会分别显示。
相当于一个echo-server
。
3. 使用系统socket编写网络程序
如果你了解socket编写程序的步骤,加上你看懂了socket.cc
和address.cc
这两个类的代码;
直接调用它的接口就好了。
TCPSocket cln_skt;Address peer_address( host, "http");cln_skt.connect( peer_address );// Address pa = cln_skt.peer_address();// std::cout << pa.to_string() << std::endl;std::string http_req_str("GET ");http_req_str.append( path );http_req_str.append(" HTTP/1.1\r\nHost: cs144.keithw.org\r\nConnection: close\r\n\r\n");cln_skt.write( http_req_str);std::string rsp;while ( !cln_skt.eof()) {rsp.clear();cln_skt.read( rsp );std::cout << rsp;}cln_skt.close();
4. 实现内存中的可靠字节流
4.1 实验描述
这个实验的目的是,在内存中实现和在上面网络通信中相类似的可靠字节流。
字节流是有限的,写入端可以终止输入;当读入端读到EOF
时,就不能再继续读了。
这个字节流在内存中是需要控制大小的,字节流会控制在任意时刻写入流的大小,它不会超过它的存储容量,直到当读入端新读出了一些数据,写入端才又可以重新写东西。这个字节流是在单线程下工作的,不用考虑读写竞争的问题。
4.2 实现
- bytestream.cc
#include "byte_stream.hh"using namespace std;ByteStream::ByteStream( uint64_t capacity ) : capacity_( capacity ) {}void Writer::push( string data ) noexcept
{// (void)data; // Your code here.if ( is_closed_ ) {this->error_ = true;return ;}auto sz = data.size();if ( sz > available_capacity()) {//std::cout << "string greater than capacity!!!" << std::endl;}auto pushBytes = std::min( sz, available_capacity());if ( 0 == pushBytes )return;// auto edit = std::find(data.begin(), data.begin() + pushBytes, EOF);// if ( edit != data.begin() + pushBytes) {// pushBytes = static_cast<uint64_t>( std::distance(data.begin(), edit ) );// is_closed_ = true;// }for (uint64_t i = 0; i < pushBytes; ++i) {if ( EOF == data[i] ) {pushBytes = i;is_closed_ = true;break;}// pushStr.push_back( data[i] );}tot_bytes_pushed_ += pushBytes;cur_bytes_buffered += pushBytes;// buffers.push( data.substr(0, pushBytes));// buffers.emplace( data.substr(0, pushBytes));buffers.emplace( std::string_view(data.begin(), data.begin() + pushBytes));}void Writer::close() noexcept
{is_closed_ = true;// Your code here.
}bool Writer::is_closed() const noexcept
{return is_closed_; // Your code here.
}uint64_t Writer::available_capacity() const noexcept
{// Your code here.return capacity_ - cur_bytes_buffered;
}uint64_t Writer::bytes_pushed() const noexcept
{return tot_bytes_pushed_; // Your code here.
}string_view Reader::peek() const noexcept
{if ( buffers.empty()) {return "";}return std::string_view{buffers.front().begin() + lazy_pointer, buffers.front().end()};// Your code here.
}void Reader::pop( uint64_t len ) noexcept
{if ( 0 == len ) {return;}if ( buffers.empty()) {return;}while ( len > 0 && cur_bytes_buffered > 0) {std::string& s = buffers.front();auto real_sz = s.size() - lazy_pointer;auto pop_bytes = min( static_cast<uint64_t>( real_sz), len);if ( len >= real_sz ) {buffers.pop();lazy_pointer = 0;}else {lazy_pointer += pop_bytes;// s.erase(0, len);}len -= pop_bytes;cur_bytes_buffered -= pop_bytes;tot_bytes_poped_ += pop_bytes;}// (void)len; // Your code here.
}bool Reader::is_finished() const noexcept
{return is_closed_ && buffers.empty(); // Your code here.
}uint64_t Reader::bytes_buffered() const noexcept
{return cur_bytes_buffered; // Your code here.
}uint64_t Reader::bytes_popped() const noexcept
{return tot_bytes_poped_; // Your code here.
}
- bytestream.h
#pragma once#include <cstdint>
#include <string>
#include <string_view>
#include <queue>
#include <algorithm>
#include <iostream>class Reader;
class Writer;class ByteStream
{
public:explicit ByteStream( uint64_t capacity );// Helper functions (provided) to access the ByteStream's Reader and Writer interfacesReader& reader();const Reader& reader() const;Writer& writer();const Writer& writer() const;void set_error() noexcept{ error_ = true; }; // Signal that the stream suffered an error.bool has_error() const noexcept{ return error_; }; // Has the stream had an error?protected:// Please add any additional state to the ByteStream here, and not to the Writer and Reader interfaces.uint64_t capacity_;bool error_ {};std::queue<std::string> buffers{};bool is_closed_{ false };uint64_t cur_bytes_buffered{};uint64_t tot_bytes_pushed_{};uint64_t tot_bytes_poped_{};size_t lazy_pointer{};
};class Writer : public ByteStream
{
public:void push( std::string data ) noexcept; // Push data to stream, but only as much as available capacity allows.void close() noexcept; // Signal that the stream has reached its ending. Nothing more will be written.bool is_closed() const noexcept; // Has the stream been closed?uint64_t available_capacity() const noexcept; // How many bytes can be pushed to the stream right now?uint64_t bytes_pushed() const noexcept; // Total number of bytes cumulatively pushed to the stream
};class Reader : public ByteStream
{
public:std::string_view peek() const noexcept; // Peek at the next bytes in the buffervoid pop( uint64_t len ) noexcept; // Remove `len` bytes from the bufferbool is_finished() const noexcept; // Is the stream finished (closed and fully popped)?uint64_t bytes_buffered() const noexcept; // Number of bytes currently buffered (pushed and not popped)uint64_t bytes_popped() const noexcept; // Total number of bytes cumulatively popped from stream
};/** read: A (provided) helper function thats peeks and pops up to `max_len` bytes* from a ByteStream Reader into a string;*/
void read( Reader& reader, uint64_t max_len, std::string& out );