写在前面:
这周开始学习斯坦福CS144计算机网络,之前看过哈工大的计算机网络的mooc以及计算机网络自顶向下这本书,对五层网络模型以及TCP/IP协议有过一定了解,但是没有实际的用代码实践过,因此选择CS144这门课作为实践。
我使用的电脑是M1 MAC,用的是CS144建议的MTU虚拟机以及提供的对应的虚拟机镜像。这里只记录代码实验。
实验部分:
一、writing a network program using an OS stream socket
- 这个实验是用TCP socket写一个webget程序,实现telnet获取网页的功能,并将回复信息打印出来
- 向web server请求网页的格式是:
- GET /PATH HTTP/1.1
- HOST: URL
- Connection:close
- 在lab中用/r/n表示换行,当web server收到close消息时,会向client发送EOF表明服务器回复完毕。
- 代码如下:
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).
cerr << "Function called: get_URL(" << host << ", " << path << ").\n";
cerr << "Warning: get_URL() has not been implemented yet.\n";
string request="GET "+path+
"HTTP/1.1\r\nHost:"+host+"\r\nConnection:close\r\n\r\n";
TCPSocket localhost;
localhost.connect(Address(host,"http"));
localhost.write(request);
while(!localhost.eof()){
cout<<localhost.read(1);
}
localhost.close();
}
二、An in-memory reliable byte stream
- 本实验是实现一个字节流类,字节流类在内存中的缓存大小有限
- writer允许向字节流中写入有限个字节,超过限制则不再写入,直到reader将字节流中的字节读完
- 字节流类中设置了如下类成员对象:
- cap:表明字节流允许存储的字节大小
- sz:表明字节流中此时已经存储了的字节大小
- totalwrite:writer向字节流中总共写入的字节数
- totalread:reader向字节流中总共读取的字节数
- end:表明input是否结束
- memory:存储在字节流中的字节
- 代码如下:
//byte_stream.hh
class ByteStream {
private:
// Your code here -- add private members as necessary.
size_t cap;
size_t sz;
size_t totalwrite,totalread;
std::string memory;
bool end;
// 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.
......
//byte_stream.cc
ByteStream::ByteStream(const size_t capacity):cap(capacity),sz(0),totalwrite(0),totalread(0),memory(""),end(false){}
size_t ByteStream::write(const string &data) {
if(sz==cap){
return 0;
}
else if(data.size()+sz<=cap){
memory+=data;
sz+=data.size();
totalwrite+=data.size();
return data.size();
}
memory+=data.substr(0,cap-sz);
size_t res=cap-sz;
sz=cap;
totalwrite+=res;
return res;
}
//! \param[in] len bytes will be copied from the output side of the buffer
string ByteStream::peek_output(const size_t len) const {
if(len>=sz) return memory;
return memory.substr(0,len);
}
//! \param[in] len bytes will be removed from the output side of the buffer
void ByteStream::pop_output(const size_t len) {
if(len>=sz){
memory="";
totalread+=sz;
sz=0;
}
else{
totalread+=len;
sz=sz-len;
memory=memory.substr(len);
}
}
//! 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) {
string res=peek_output(len);
pop_output(len);
return res;
}
void ByteStream::end_input() {end=true;}
bool ByteStream::input_ended() const {return end;}
size_t ByteStream::buffer_size() const { return sz; }
bool ByteStream::buffer_empty() const { return sz==0; }
bool ByteStream::eof() const { if(end && sz==0) return true;
return false; }
size_t ByteStream::bytes_written() const { return totalwrite; }
size_t ByteStream::bytes_read() const { return totalread; }
size_t ByteStream::remaining_capacity() const { return cap-sz; }
|