CS144 Lab0
这里回顾CS 144 Lab 0: networking warmup。
实验资料:
- https://www.cnblogs.com/kangyupl/p/stanford_cs144_labs.html
- https://kangyupl.gitee.io/cs144.github.io/
- https://gitee.com/kangyupl/sponge
Lab 0: networking warmup
2 Networking by hand
2.1
2
telnet cs144.keithw.org http
Trying 104.196.238.229...
Connected to cs144.keithw.org.
Escape character is '^]'.
GET /hello HTTP/1.1
Host: cs144.keithw.org
HTTP/1.1 200 OK
Date: Sat, 13 Nov 2021 03:32:18 GMT
Server: Apache
Last-Modified: Thu, 13 Dec 2018 15:45:29 GMT
ETag: "e-57ce93446cb64"
Accept-Ranges: bytes
Content-Length: 14
Content-Type: text/plain
Hello, CS144!
3
telnet cs144.keithw.org http
GET /lab0/123 HTTP/1.1
Trying 104.196.238.229...
Connected to cs144.keithw.org.
Escape character is '^]'.
Host: cs144.keithw.org
HTTP/1.1 200 OK
Date: Sat, 13 Nov 2021 03:35:44 GMT
Server: Apache
X-You-Said-Your-SunetID-Was: 123
X-Your-Code-Is: 792558
Content-length: 107
Vary: Accept-Encoding
Content-Type: text/plain
Hello! You told us that your SUNet ID was "123". Please see the HTTP headers (above) for your secret code.
2.2
由于没有sunetid,所以无法发送:
telnet smtp-unencrypted.stanford.edu smtp
HELO mycomputer.stanford.edu
MAIL FROM: sunetid@stanford.edu
RCPT TO: sunetid@stanford.edu
DATA
From: sunetid@stanford.edu
To: sunetid@stanford.edu
Subject: Hello from CS144 Lab 0!
hello
.
quit
2.3
netcat:
netcat -v -l -p 9090
Listening on [0.0.0.0] (family 0, port 9090)
Connection from localhost 56596 received!
123
456
^C
telnet:
telnet localhost 9090
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
123
456
Connection closed by foreign host.
3 Writing a network program using an OS stream socket
准备工作
git clone https://gitee.com/kangyupl/sponge
git checkout -b master origin/master
mkdir build && cd build
cmake ..
make format
make -j4 && make check_lab0
代码
说明:
- webget是一个使用操作系统的TCP支持和流套接字抽象在Internet上获取网页的程序,就像您在本实验室前面手动完成的一样。
代码位置:
/home/cs144/sponge/apps/webget.cc:
void get_URL(const string &host, const string &path) {
// Your code here.
// You will need to connect to the "http" service on
// the computer whose name is in the "host" string,
// then request the URL path given in the "path" string.
// Then you'll need to print out everything the server sends back,
// (not just one call to read() -- everything) until you reach
// the "eof" (end of file).
Address address(host, "http");
TCPSocket socket;
// 和服务器连接
socket.connect(address);
// request
socket.write("GET " + path + " HTTP/1.1\r\n");
socket.write("HOST: " + host + "\r\n");
socket.write("\r\n");
// request结束
socket.shutdown(SHUT_WR);
// content
while (!socket.eof()) {
std::cout << socket.read(1);
}
// close
socket.close();
}
测试
测试1,参考2.1:
make && ./apps/webget cs144.keithw.org /hello
结果:
HTTP/1.1 200 OK
Date: Sun, 12 Dec 2021 07:47:48 GMT
Server: Apache
Last-Modified: Thu, 13 Dec 2018 15:45:29 GMT
ETag: "e-57ce93446cb64"
Accept-Ranges: bytes
Content-Length: 14
Content-Type: text/plain
Hello, CS144!
测试2:
make check_webget
结果:
[100%] Testing webget...
Test project /home/cs144/sponge/build
Start 27: t_webget
1/1 Test #27: t_webget ......................... Passed 0.49 sec
100% tests passed, 0 tests failed out of 1
Total Test time (real) = 0.50 sec
[100%] Built target check_webge
4 An in-memory reliable byte stream
说明
到现在为止,你已经看到了可靠的无序字节流的抽象是如何在互联网上进行通信的,尽管互联网本身只提供了”尽力而为”(不可靠)的数据报服务。
为了完成本周的实验,你将在一台计算机的内存中实现一个提供这种抽象的对象。(你可能在CS 110中做过类似的事情。) 字节在 “输入”端写入,并可以从”输出”端以同样的顺序读取。字节流是有限的:writer可以结束输入,然后就不能再写了。当reader读到流的末端时,它将到达”EOF”(结束),不再有更多的字节可以被读取。
你的字节流也会受到控制:它被初始化时有一个特定的容量:它愿意在自己的内存中存储的最大字节数。字节流将限制writer可以写多长的字符串,以确保字节流不会超过其存储容量。当reader读取字节并将其从流中耗尽时,writer被允许写入更多。
你的字节流是在单线程中使用的——你不必担心并发的writer/reader、锁定或竞争条件。
设计
- 一个缓存区,一端读,一端写,先进先出,这里使用的是list;
代码
byte_stream.hh:
#ifndef SPONGE_LIBSPONGE_BYTE_STREAM_HH
#define SPONGE_LIBSPONGE_BYTE_STREAM_HH
#include <cstddef>
#include <cstdint>
#include <deque>
#include <list>
#include <string>
#include <utility>
//! \brief An in-order byte stream.
//! Bytes are written on the "input" side and read from the "output"
//! side. The byte stream is finite: the writer can end the input,
//! and then no more bytes can be written.
class ByteStream {
private:
// Your code here -- add private members as necessary.
// list作为缓存
std::list<char> buf = {};
size_t size;
// 0, start, end
size_t read_cnt = 0;
size_t write_cnt = 0;
bool is_end = 0;
bool _error{}; //!< Flag indicating that the stream suffered an error.
public:
//! Construct a stream with room for `capacity` bytes.
ByteStream(const size_t capacity);
//! \name "Input" interface for the writer
//!@{
//! Write a string of bytes into the stream. Write as many
//! as will fit, and return how many were written.
//! \returns the number of bytes accepted into the stream
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() { _error = true; }
//!@}
//! \name "Output" interface for the reader
//!@{
//! Peek at next "len" bytes of the stream
//! \returns a string
std::string peek_output(const size_t len) const;
//! Remove 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
//! \returns a vector of bytes read
std::string read(const size_t len) {
const auto ret = peek_output(len);
pop_output(len);
return ret;
}
//! \returns `true` if the stream input has ended
bool input_ended() const;
//! \returns `true` if the stream has suffered an error
bool error() const { return _error; }
//! \returns the maximum amount that can currently be read from the stream
size_t buffer_size() const;
//! \returns `true` if the buffer is empty
bool buffer_empty() const;
//! \returns `true` if the output has reached the ending
bool eof() const;
//!@}
//! \name General accounting
//!@{
//! Total number of bytes written
size_t bytes_written() const;
//! Total number of bytes popped
size_t bytes_read() const;
//!@}
};
#endif // SPONGE_LIBSPONGE_BYTE_STREAM_HH
byte_stream.cc:
#include "byte_stream.hh"
#include <algorithm>
#include <iterator>
#include <stdexcept>
// Dummy implementation of a flow-controlled in-memory byte stream.
// For Lab 0, please replace with a real implementation that passes the
// automated checks run by `make check_lab0`.
// You will need to add private members to the class declaration in `byte_stream.hh`
template <typename... Targs>
void DUMMY_CODE(Targs &&... /* unused */) {}
using namespace std;
ByteStream::ByteStream(const size_t capacity) : size(capacity) {
}
// write字符, 最多缓存至capacity长度
size_t ByteStream::write(const string &data) {
int l1 = size - buf.size();
int l2 = data.size();
int l = min(l2, l1);
int i;
for (i = 0; i < l; i++) {
buf.push_back(data[i]);
// 更新计数
write_cnt++;
}
return i;
}
//! \param[in] len bytes will be copied from the output side of the buffer
// 返回buf中前min(len, size)个字符
string ByteStream::peek_output(const size_t len) const {
string res;
int l1 = buf.size();
int l2 = len;
int l = min(l1, l2);
int i = 0;
for (auto it = buf.begin(); (it != buf.end()) && (i < l); i++, it++) {
res.push_back(*it);
}
return res;
}
//! \param[in] len bytes will be removed from the output side of the buffer
// 弹出buf中前min(len, size)个字符
void ByteStream::pop_output(const size_t len) {
int l1 = buf.size();
int l2 = len;
int l = min(l1, l2);
for (int i = 0; i < l; i++) {
buf.pop_front();
// 更新计数
read_cnt++;
}
}
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 buffer_size() == 0; }
// 判断条件
// buffer为空, 并且输入结束
bool ByteStream::eof() const { return buffer_empty() && input_ended(); }
size_t ByteStream::bytes_written() const { return write_cnt; }
size_t ByteStream::bytes_read() const { return read_cnt; }
size_t ByteStream::remaining_capacity() const { return size - buf.size(); }
测试
测试:
make -j4 && make check_lab0
结果:
Test project /home/cs144/sponge/build
Start 22: t_byte_stream_construction
1/9 Test #22: t_byte_stream_construction ....... Passed 0.00 sec
Start 23: t_byte_stream_one_write
2/9 Test #23: t_byte_stream_one_write .......... Passed 0.00 sec
Start 24: t_byte_stream_two_writes
3/9 Test #24: t_byte_stream_two_writes ......... Passed 0.00 sec
Start 25: t_byte_stream_capacity
4/9 Test #25: t_byte_stream_capacity ........... Passed 0.00 sec
Start 26: t_byte_stream_many_writes
5/9 Test #26: t_byte_stream_many_writes ........ Passed 0.01 sec
Start 27: t_webget
6/9 Test #27: t_webget ......................... Passed 0.43 sec
Start 47: t_address_dt
7/9 Test #47: t_address_dt ..................... Passed 0.01 sec
Start 48: t_parser_dt
8/9 Test #48: t_parser_dt ...................... Passed 0.00 sec
Start 49: t_socket_dt
9/9 Test #49: t_socket_dt ...................... Passed 0.00 sec
100% tests passed, 0 tests failed out of 9
Total Test time (real) = 0.47 sec
[100%] Built target check_lab0
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
评论
ValineLivere