CS144实验记录(一)lab0
环境搭建
按照官网要求搭建环境
2.1 Fetch a Web page
使用Telnet 获取http://cs144.keithw.org/hello页面的内容
- 在虚拟机中,输入
telnet cs144.keithw.org http ,This tells the telnet program to open a reliable byte stream between your computer and another computer (named cs144.keithw.org), and with a particular service running on that computer: the “http” service - Type
GET /hello HTTP/1.1 . This tells the server the path part of the URL. - Type Host:
cs144.keithw.org . This tells the server the host part of the URL. - Type
Connection: close . This tells the server that you are finished making requests, and it should close the connection as soon as it finishes replying. - Hit the Enter key one more time: . This sends an empty line and tells the server that you are done with your HTTP request.
完成后,就可以在终端上看到与在浏览器中访问该页面一样的信息。
2.3 Listening and connecting
我们已经看到Telnet是什么:与在其他计算机上运行的程序建立连接的客户端程序。我们还可以使用netcat 成为一个简单的服务器(即等待客户端连接到它的程序)
- In one terminal window, run
netcat -v -l -p 9090 on your VM. You should see: - Leave netcat running. In another terminal window, run
telnet localhost 9090 - If all goes well, the netcat will have printed something like “Connection from localhost 53500 received!”.
- 现在我们可以在任意一个终端中输入文字,按下回车后,另一个终端就将其会打印在屏幕上
3 Writing a network program using an OS stream socket
In this lab, you will simply use the operating system’s pre-existing support for the Transmission Control Protocol. You’ll write a program called “webget” that creates a TCP stream socket, connects to a Web server, and fetches a page—much as you did earlier in this lab.
In particular, we would like you to:
- Use the language documentation at https://en.cppreference.com as a resource
- Never use
malloc() or free() . - Never use
new or delete . - Essentially never use raw pointers (*), and use “smart” pointers (
unique_ptr or shared_ptr ) only when necessary. (You will not need to use these in CS144.) - Avoid templates, threads, locks, and virtual functions. (You will not need to use these in CS144.)
- Avoid C-style strings (
char *str ) or string functions (strlen() , strcpy() ). These are pretty error-prone. Use a std::string instead. - Never use C-style casts (e.g.,
(FILE *)x ). Use a C++ static_cast if you have to (you generally will not need this in CS144). - Prefer passing function arguments by
const reference (e.g.: const Address & address ). - Make every variable
const unless it needs to be mutated. - Make every method
const unless it needs to mutate the object - Avoid global variables, and give every variable the smallest scope possible.
- Before handing in an assignment, please run
make format to normalize the coding style.
Writing webget
实现webget,这是一个使用操作系统的TCP支持和流套接字抽象在Internet上提取网页的程序,就像上面使用telnet进行的操作一样。要求使用提供的TCPSocket 和Address 类。
实际上就是创建一个TCP套接字然后与目标主机建立连接,然后构造http的GET请求,通过socket发送出去,socket再接收响应并打印出来。
void get_URL(const string &host, const string &path) {
TCPSocket sock;
sock.connect(Address(host,"80"));
std::string send,recv;
send="GET "+path+" HTTP/1.1\r\n"+"Host:"+host+"\r\n"+"Connection:close\r\n\r\n";
sock.write(send);
while(sock.eof()==false){
sock.read(recv);
std::cout<<recv;
}
sock.close();
}
4 An in-memory reliable byte stream
要求实现一个有序字节流类,使之支持读写、容量控制,实际上就是类似于TCP的流量控制。这个字节流类似于一个带容量的队列,从一头读,从另一头写。当流中的数据达到容量上限时,便无法再写入新的数据。特别的,读操作被分为了peek和pop两步。peek为从头部开始读取指定数量的字节,pop为弹出指定数量的字节。
要求:
数据结构:由于queue 只能访问开头的节点,所以使用deque<char> 实现。将输入的string 中的char一个个push到deque中,接收端再从deque中读取相应长度的char。
byte_stream.hh
class ByteStream {
private:
bool _error=false;
size_t _capacity = 0;
std::deque<char>_buffer={};
bool _input_ended_flag=false;
size_t _write_count=0;
size_t _read_count=0;
}
byte_stream.cc
ByteStream::ByteStream(const size_t capacity):_capacity(capacity) { }
size_t ByteStream::write(const string &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;
}
string ByteStream::peek_output(const size_t len) const {
size_t length=len;
if(len>_buffer.size())
length=_buffer.size();
return string().assign(_buffer.begin(),_buffer.begin()+length);
}
void ByteStream::pop_output(const size_t len) {
size_t length=len;
if(len>_buffer.size())
length=_buffer.size();
_read_count+=length;
for(;length>0;length--)
_buffer.pop_front();
return;
}
std::string ByteStream::read(const size_t len) {
string s=peek_output(len);
pop_output(len);
return s;
}
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.empty();
}
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();
}
|