Stanford CS144 Lab0.Network WarmUp
于2022年3月3日2022年3月3日由Sukuna发布
现在我就用这个实验的内容复习一遍计算机网络的知识.
1 Networking by hand
这一个部分主要是体验一些基本的应用层协议,主要是HTTP协议和SMTP协议.
Both of these tasks rely on a networking abstraction called a reliable bidirectional in-order byte stream: you’ll type a sequence of bytes into the terminal, and the same sequence of bytes will eventually be delivered, in the same order, to a program running on another computer (a server). The server responds with its own sequence of bytes, delivered back to your terminal.
在实验资料中给出的是这么一段话,这句话的意思就是所有的应用层协议都是由底层支撑的,这个底层可以理解成可靠的二进制比特流的传输,一方应用程序会产生比特流投入到传输通道中,另一方的应用程序会从传输通道中获取到比特流信息.这个传输通道就是Socket,套接字.
1.1 获取一个网页.
我们跟随着实验的步骤来进行执行.
1)首先用浏览器打开网页http://cs144.keithw.org/hello.
发现内容就是简短的一行字 Hello,CS144.
2) 用telnet进行连接,输入telnet cs144.keithw.org http
这一步的做法就是在你的电脑和另一台电脑(域名为cs144.keithw.org)进行一个套接字连接,(原文:a reliable byte stream between your computer and anothercomputer),这个时候你的电脑和cs144.keithw.org(获取这个域名的IP需要通过DNS服务器进行)就连接上了.
3)输入GET /hello HTTP/1.1
这个是HTTP协议的应用,HTTP协议的命令有GET和POST两种,其中POST一般就是投放一个表单到服务器上,GET就是从服务器获取资源.其中资源的名称是可以指定的,uri就是指定资源, 一般uri的组成就是 服务器的域名 资源在服务器的根目录的对应的文件位置.比如说hust.edu.cn/1.jpg,就是在hust.edu.cn这个服务器根目录下的1.jpg这个文件.
这个命令就是用HTTP/1.1的方式获取服务器的资源
4) 输入 Host: cs144.keithw.org
这个指定host的地址,因为一个uri的构成就是域名 文件位置.
上面几个做法就是利用telnet软件制作一个HTTP请求报文.请求报文分成头部和请求本身
这个时候就会返回一个HTTP响应报文:
代码语言:javascript复制HTTP/1.1 200 OK
Date: Thu, 03 Mar 2022 07:53:25 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!
其中分成第一行,首部和报文内容,第一行表示使用的HTTP版本,状态码和短语,我们可以利用状态码和短语来判断服务器是否正常响应了我们的请求:
首部就蕴含了一些控制信息,比如说报文长度和报文类型等.最后的就是报文内容,就是主体部分.
5) 获得sunsetid
如法炮制:构造请求报文和响应报文即可.
1.2 给自己发送邮件
1) 首先连接到服务器,这里要使用SMTP协议进行连接.
2) 给服务器打招呼
3) 登陆
注意这里是BASE64编码的,第一行语句表示Username:,就输入你的邮箱地址,第二行语句表示授权码,把授权码转化成BASE64编码的即可.
4) 写邮件
MAIL 命令,发件人
RCPT 命令,收件人
DATA表示开始书写新建内容
.表示书写结束
1.3 监听服务器
1) 使用netcat -v -l -p 9090创建一个监听端口.
2) 连接本机创建的监听端口:telnet localhost 9090
这个时候客户端和服务器连接上了.
HTTP的连接本质上是C/S模型:客户-服务器模型,在上文我们提到了管道的观念,其实服务器一直在一个管道上监听信息,一旦监听到了信息就对应地往管道里面投放信息.
总的来说,就是客户端向服务器提出申请请求,服务器一直在监听客户端的申请请求,一有申请请求就立刻建立TCP连接.
2 自制Socket
This feature is known as a stream socket. To your program and to the Web server, the socket looks like an ordinary file descriptor (similar to a file on disk, or to the stdin or stdout I/O streams). When two stream sockets are connected, any bytes written to one socket will eventually come out in the same order from the other socket on the other computer.
Socket在Linux操作系统中本质上就是一个文件,一旦两个Socket相互连接,应用程序会往一个Socket递交数据,另外一个Socket就会原封不动地把数据传递过来.连接的方式在运输层有讲,客户端的一个网络端口创建一个Socket,往服务器的一个网络端口发送请求,这是第一次握手,接着服务器的网络端口传输ACK给客户端,这是第二次握手,接着客户端会传输一个最后的请求,这个叫三次握手.三次握手后,连接就完成了,这个时候两个Socket(可以理解成网络端口?)相互链接了.
需要注意的是,在应用层我们一般是注重逻辑通信,Socket是一个逻辑概念,应用程序把数据投给一个叫做Socket的东西,你可以理解成逻辑通信的一端,但是具体Socket往下是怎么做的不是应用程序需要关注的.
这个实验就需要我们模拟一个Socket应用,与一个服务器的端口建立连接.然后获取网页.
代码语言:javascript复制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 rearequestd() -- everything) until you reach
// the "eof" (end of file).
// create a TCPSocket
TCPSocket client_socket;
// connect with host. host is a parameter.
client_socket.connect(Address(host, "http"));
// send a request Message. the request is made of 2 sentences.
string request = "GET " path " HTTP/1.1rn" "Host: " host "rnConnection: closernrn";
client_socket.write(request);
// get the Message
while(!client_socket.eof()){
string reply = client_socket.read();
cout<<reply;
}
cerr << "Function called: get_URL(" << host << ", " << path << ").n";
cerr << "Warning: get_URL() has not been implemented yet.n";
}
这个时候先创建一个TCPSocket,首先先进行连接,然后像之前一样创建request,接着这个Socket就可以把request写进去.然后服务器会返回数据,这个数据是读取到Socket的,读数据一直读到EOF即可.
由于这个实验是面向初学者的,具体Socket怎么读怎么写我们没有考虑,我们只用调用教授已经写好的写,读操作.
3 缓冲区队列
要求实现一个有序字节流类(in-order byte stream),使之支持读写、容量控制。这个字节流类似于一个带容量的队列,从一头读,从另一头写。当流中的数据达到容量上限时,便无法再写入新的数据。特别的,写操作被分为了peek和pop两步。peek为从头部开始读取指定数量的字节,pop为弹出指定数量的字节。
总的来说就是做一个桶,可以从下方获得内容,也可以从上方添加内容,当桶满的时候就不可以添加东西了
ByteStream具有一定的容量,最大允许存储该容量大小的数据;在读取端读出一部分数据后,它会释放掉已经被读出的内容,以腾出空间继续让写端写入数据。
这个实验为我们后期实现TCP协议有着帮助.
上面的是缓冲区队列的一些声明,对于读写两方,操作是不同的.
有个小提示,如果C 的构造函数可以使用像这样的方法进行初始化的
代码语言:javascript复制class baba (const int abab) _abab(abab){
}
这个本质上就是数据结构题,完成缓冲区队列罢了.