Code Style
- 使用 https://en.cppreference.com 作为C++参考手册
- 杜绝使用
malloc() / free()
或new / delete
- 杜绝使用C风格的类型转换,而使用C++
static_cast
- 尽量使用智能指针而非C风格指针
- 尽量使用 C++
std::string
而非C风格字符串及相关API函数 - 尽量使用
const reference
类型的函数参数 - 尽量使用
const
类型的变量或函数 - 尽量不使用全局变量,并且赋予变量尽可能小的作用域
- 使用
clang-format
对代码做格式化,使用clang-tidy
对代码做静态检查
Abstract
了解 TCP writer 和 reader 之间的可靠字节流传输
Fetch a Web page
使用 telnet
手动构造 HTTP 报文,实现 HTTP 协议通信
cs144@cs144vm:~$ telnet cs144.keithw.org http
Trying 104.196.238.229...
Connected to cs144.keithw.org.
Escape character is '^]'.
GET /lab0/1234 HTTP/1.1
Host: cs144.keithw.org
Connection: close
HTTP/1.1 200 OK
Date: Thu, 30 Jan 2025 10:48:57 GMT
Server: Apache
X-You-Said-Your-SunetID-Was: 1234
X-Your-Code-Is: 222626
Content-length: 108
Vary: Accept-Encoding
Connection: close
Content-Type: text/plain
Hello! You told us that your SUNet ID was "1234". Please see the HTTP headers (above) for your secret code.
Connection closed by foreign host.
Send yourself a mail
使用 telnet
手动构造 SMTP 报文,实现 SMTP 协议通信
cs144@cs144vm:~$ telnet smtp.126.com smtp
Trying 117.135.214.14...
Connected to smtp.126.com.
Escape character is '^]'.
220 126.com Anti-spam GT for Coremail System (126com[20140526])
HELO hartvon
250 OK
AUTH LOGIN
334 dXNlcm5hbWU6
Zmh0enZsQDEyNi5jb20=
334 UGFzc3dvcmQ6
Qlhwdjk2SHl1clpjZlBNVQ==
235 Authentication successful
MAIL FROM: <fhtzvl@126.com>
250 Mail OK
RCPT TO: <fhtzvl@163.com>
250 Mail OK
DATA
354 End data with <CR><LF>.<CR><LF>
FROM: fhtzvl@126.com
TO: fhtzvl@163.com
Subject: Hello from CS144 Lab 0!
This is example text body.
.
250 Mail OK queued as gzsmtp3,PikvCgDnP+X3bZtns8SpAQ--.16071S2 1738239576
421 closing transmission channel
Connection closed by foreign host.
Listenning and connecting
使用 nc 进行 TCP 层 server 和 client 之间的通信
cs144@cs144vm:~/minnow$ nc -vlp 9090
Listening on 0.0.0.0 9090
Connection received on localhost 48480
hello, this is client
cs144@cs144vm:~/minnow$ nc localhost 9090
hello, this is client
^C
Writing webget
使用封装好的 TCPSocket 类手动构造 HTTP 报文,并与连接成功的服务端进行报文的写读
void get_URL( const string& host, const string& path )
{
cerr << "Function called: get_URL(" << host << ", " << path << ")\n";
try {
TCPSocket tcp_socket; // 3-way shakehands
tcp_socket.connect( Address( host, "http" ) );
tcp_socket.write(
{ "GET " + path + " HTTP/1.1\r\n", "Host: cs144.keithw.org\r\n", "Connection: close\r\n\r\n" } ); // client's P & server's F
while ( !tcp_socket.eof() ) { // check if reach elf
std::string output;
tcp_socket.read( output ); // may set elf status
std::cout << output;
}
// client's F as tcp_socket's destruction
} catch ( const std::exception& e ) {
std::cerr << e.what() << "\n";
}
}
An in-memory reliable byte stream
将内存 buffer 作为 TCP 的字节流 buffer,实现 TCP 字节流的 push 和 pop,通过 capacity_控制 writer 的写限速,超出容量的字节流将会被丢弃
注意:虽然这个内存buffer有最大容量(限制了一次从内存中写入或读取的最大字节长度),但它所承载的总字节流可以任意长,只要这些字节流一直被不断地被写入和读取
// bytes_stream.hh
class ByteStream
{
public:
...
protected:
uint64_t capacity_;
bool error_ {};
bool is_closed_ {};
std::string buffer_ {};
uint64_t bytes_buffered_ {};
uint64_t bytes_write_ {};
uint64_t bytes_read_ {};
};
// bytes_stream.cc
#include "byte_stream.hh"
using namespace std;
ByteStream::ByteStream( uint64_t capacity ) : capacity_( capacity ) {}
void Writer::push( string data )
{
if ( is_closed_ or has_error() )
return;
auto data_size = std::min( data.size(), available_capacity() );
buffer_ += data.substr( 0, data_size );
bytes_buffered_ += data_size;
bytes_write_ += data_size;
}
void Writer::close()
{
is_closed_ = true;
}
bool Writer::is_closed() const
{
return is_closed_;
}
uint64_t Writer::available_capacity() const
{
return capacity_ - bytes_buffered_;
}
uint64_t Writer::bytes_pushed() const
{
return bytes_write_;
}
string_view Reader::peek() const
{
return buffer_;
}
void Reader::pop( uint64_t len )
{
buffer_.erase( 0, len );
bytes_read_ += len;
bytes_buffered_ -= len;
}
bool Reader::is_finished() const
{
return is_closed_ and bytes_buffered_ == 0;
}
uint64_t Reader::bytes_buffered() const
{
return bytes_buffered_;
}
uint64_t Reader::bytes_popped() const
{
return bytes_read_;
}
Leave a Reply