栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

计算机网络cs144之lab0

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

计算机网络cs144之lab0

文章目录
  • 1 建立课程开发环境
  • 2 Fetch a Web page
    • 2.1 浏览器发送http请求
    • 2.2 telnet模拟浏览器发送http请求
  • 3 WebGet
  • 4 An in-memory reliable byte stream(缓冲区队列)

1 建立课程开发环境

课程使用的是基于Linux的系统,可以使用ubuntu发行版。(安装过程略过)
可参考:https://blog.csdn.net/u_hcy2000/article/details/121506905?spm=1001.2014.3001.5501

2 Fetch a Web page

使用telnet来体会浏览器是如何通过HTTP协议从服务器获取一个页面(HTML文档)的

2.1 浏览器发送http请求
  1. 通过浏览器发送 http://cs144.keithw.org/hello 请求
  2. 查看页面响应结果:Hello, CS144!
2.2 telnet模拟浏览器发送http请求

键入 telnet cs144.keithw.org http,http请求与服务器建立连接
键入 GET /hello HTTP/1.1 ,这句话告诉服务器 URL 的路径(path)
键入 Host: cs144.keithw.org 这告诉服务器 URL 的主机(host)
键入Connection: close 结束请求
键入 空行,完成了http请求

查看服务器的响应信息如下:

扩展:HTTP请求简介
设计 HTTP 最初的目的是为了提供一种发布和接收 HTML 页面的方法。
HTTP 请求一共分为四个部分:请求行,请求头,空行,请求体。

HTTP响应报文格式:响应行、响应头、空行、响应体 四个部分。

3 WebGet

使用TCPSocket来实现发送http请求,并获取响应信息,打印出来。

  1. 创建一个TCPSocket并与服务器建立连接。
  2. 向服务器发送请求,格式参照前面fetch a web page部分,注意在HTTP中每行的结尾应该为rn。
  3. 发送完请求后,客户端应该关闭TCPSocket的写功能,对应前面的Connection:close,告诉服务器请求已经发送完毕,服务器只要回复完数据后就可以立刻断开连接。
  4. 循环读取从服务器发送过来的信息,直到遇到EOF(end of file)。 最后记得需要关闭前面创建的TCPSocket。

课程代码:

void get_URL(const string &host, const string &path) {
    // telnet cs144.keithw.org http
    // GET /hello HTTP/1.1
    // Host: cs144.keithw.org
    // Connection: close

    // 创建一个客户端对象
    TCPSocket client_socket;
    // 与服务器建立TCP连接
    client_socket.connect(Address(host, "http"));
    // 客户端发送请求request
    string reqMsg = "GET "+path+" HTTP/1.1rn"+"Host: "+host+"rnConnection: closernrn";
    client_socket.write(reqMsg);

    // 客户端接收服务端的响应response
    while(!client_socket.eof()){
        string recvMsg = client_socket.read();
        cout< 
4 An in-memory reliable byte stream(缓冲区队列) 

自定义一个字节流类型。
因特网本身并不提供对传输“可靠性”的保证,而是由客户端和服务器上的操作系统来完成这个任务。我们现在要实现的是位于TCP连接两端的套接字中的字节流数据结构。

ByteStream具有一定的容量,最大允许存储该容量大小的数据;在读取端读出一部分数据后,它会释放掉已经被读出的内容,以腾出空间继续让写端写入数据。
字节流以类ByteStream来实现,byte_stream.hh中声明了这个类,以及它的内部变量和成员函数;各个成员函数在 http://byte_stream.cc 中予以实现。

思路:

  1. 数据存储结构:队列
  2. 实现逻辑:注意输入端写数据,输出端输出数据两大主要操作

byte_stream.hh
// 输入端写入数据和输出端读取数据,满足先入先出的原则,可采用队列的数据结构实现缓冲区
// 注意区分,capacity代表的是缓冲区大小,buffer_size和_stream.size()代表缓冲区里实际内容的大小
class ByteStream {
  private:
    // Your code here -- add private members as necessary.

    // 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.
    
    // 创建一个缓冲区队列
    std::deque _buf{};
    // 缓冲区标准容量
    size_t _capacity = 0;
    // 输入端写入结束标志
    bool _is_end_input = false;
    // 输入端写入长度
    size_t _bytes_written = 0;
    // 输出端读取长度
    size_t _bytes_read = 0;
    
    bool _error{};  //!< Flag indicating that the stream suffered an error.
Byte_stream.cc
#include "byte_stream.hh"

template 
void DUMMY_CODE(Targs &&... ) {}

using namespace std;

// 初始化字节流数据,设置缓冲区的最大容量
ByteStream::ByteStream(const size_t capacity) { 
    _capacity = capacity;
}

// 输入端写数据,存入到缓冲队列中
size_t ByteStream::write(const string &data) {
    // 如果队列满了,返回0不能写入数据,写入为0
    if(remaining_capacity() == 0) return 0;

    // 将数据写入
    size_t write_size = (data.size() <= remaining_capacity()) ? data.size(): remaining_capacity();
    for(size_t i = 0; i < write_size; i++){
        _buf.push_back(data[i]);
    }

    // 已经写入的数据长度更新
    _bytes_written += write_size;

    return write_size;
}

// 查看缓冲区的队列内容,但是不出队列
string ByteStream::peek_output(const size_t len) const {
    size_t buf_size = (len <= buffer_size()) ? len : buffer_size();
    string data;
    data.assign(_buf.begin(),_buf.begin()+buf_size);
    
    return data;
}

// 出队列,从缓冲区中删除len长度的数据
void ByteStream::pop_output(const size_t len) {
    size_t buf_size = (len <= buffer_size()) ? len : buffer_size();
    for(size_t i = 0; i < buf_size; i++){
        _buf.pop_front();
    }
    _bytes_read += buf_size;
}

// 从缓冲区队列中读取数据
std::string ByteStream::read(const size_t len) {
    string buf_read = peek_output(len);
    pop_output(len);

    return buf_read;
}

void ByteStream::end_input() {_is_end_input = true;}

bool ByteStream::input_ended() const { return _is_end_input; }

size_t ByteStream::buffer_size() const { return _buf.size(); }

bool ByteStream::buffer_empty() const { return _buf.size() == 0; }

bool ByteStream::eof() const { return input_ended() && buffer_empty(); }

size_t ByteStream::bytes_written() const { return _bytes_written; }

size_t ByteStream::bytes_read() const { return _bytes_read; }

size_t ByteStream::remaining_capacity() const { return _capacity - _buf.size(); }

总结:就是自定义一个字节缓冲区的数据结构,这里选择使用队列数据结构来存储数据,符合缓冲区的先进先出原则,且效率比较高效。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/599652.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号