CS144 lab0: warmup

发布于:2025-06-15 ⋅ 阅读:(18) ⋅ 点赞:(0)

Lab 0: networking warmup

1. 环境

依赖配置

 sudo apt update && sudo apt install git cmake gdb build-essential clang \
 clang-tidy clang-format gcc-doc pkg-config glibc-doc tcpdump tshark

g+±13配置

  • ppa中科大源
# deb https://ppa.launchpadcontent.net/ubuntu-toolchain-r/test/ubuntu/ jammy main
deb https://launchpad.proxy.ustclug.org/ubuntu-toolchain-r/test/ubuntu/ jammy main
# deb-src https://ppa.launchpadcontent.net/ubuntu-toolchain-r/test/ubuntu/ jammy main
  • 安装g++-13 gcc-13
sudo apt install gcc-13
sudo apt install g++-13
  • 设定优先级
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 11
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13

sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 11
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13
  • 版本检查
g++ -v
gcc -v
  • cmake版本安装
git clone https://gitee.com/mirrors/CMakesource.git
./configure
make && make install

更新apt源

sudo update-alternatives --install /usr/bin/cmake cmake /usr/local/bin/cmake 1 --force

2. 使用命令获取网页

2.1 http获取网页

telnet到服务器上

telnet cs144.keithw.org http

输入http方法,指定主机,输入完成后还需要按一次enter

GET /hello HTTP/1.1 \n
Host: cs144.keithw.ort \n
\n

输入成功后可以得到

Hello, CS144!

的字样。

2.2 smtp输入邮箱

没有内网权限,跳过这个实验

2.3 本地服务器

在本地使用 netcat命令

  • 服务端
netcat -v -l -p 9090
  • 客户端
telnet localhost 9090

之后分别在客户端和服务端输入,两方都会分别显示。
相当于一个echo-server

3. 使用系统socket编写网络程序

如果你了解socket编写程序的步骤,加上你看懂了socket.ccaddress.cc这两个类的代码;
直接调用它的接口就好了。

  TCPSocket cln_skt;
  Address peer_address( host, "http");

  cln_skt.connect( peer_address );

  // Address pa = cln_skt.peer_address();
  // std::cout << pa.to_string() << std::endl;

  std::string http_req_str("GET ");
  http_req_str.append( path );
  http_req_str.append(" HTTP/1.1\r\nHost: cs144.keithw.org\r\nConnection: close\r\n\r\n");


  cln_skt.write( http_req_str);

  std::string rsp;
  while ( !cln_skt.eof()) {
    rsp.clear();
    cln_skt.read( rsp );
    std::cout << rsp;
  }

  
  cln_skt.close();
4. 实现内存中的可靠字节流
4.1 实验描述

这个实验的目的是,在内存中实现和在上面网络通信中相类似的可靠字节流。
字节流是有限的,写入端可以终止输入;当读入端读到EOF时,就不能再继续读了。
这个字节流在内存中是需要控制大小的,字节流会控制在任意时刻写入流的大小,它不会超过它的存储容量,直到当读入端新读出了一些数据,写入端才又可以重新写东西。这个字节流是在单线程下工作的,不用考虑读写竞争的问题。

4.2 实现
  • bytestream.cc
#include "byte_stream.hh"

using namespace std;

ByteStream::ByteStream( uint64_t capacity ) : capacity_( capacity ) {}

void Writer::push( string data ) noexcept
{
  // (void)data; // Your code here.
  if ( is_closed_ ) {
      this->error_ = true;
      return ;
  }


  auto sz = data.size();
  if ( sz > available_capacity()) {
    //std::cout << "string greater than capacity!!!" << std::endl;
  }
  auto pushBytes = std::min( sz, available_capacity());

  if ( 0 == pushBytes )
    return;

  // auto edit = std::find(data.begin(), data.begin() + pushBytes, EOF);
  // if ( edit != data.begin() + pushBytes) {
  //    pushBytes = static_cast<uint64_t>( std::distance(data.begin(), edit ) );
  //    is_closed_ = true;
  // }

  for (uint64_t i = 0; i < pushBytes; ++i) {
    if ( EOF == data[i] ) {
        pushBytes = i;
        is_closed_ = true;
        break;
    }
    // pushStr.push_back( data[i] );
  }

  tot_bytes_pushed_ += pushBytes;
  cur_bytes_buffered += pushBytes;

  // buffers.push( data.substr(0, pushBytes));
  // buffers.emplace( data.substr(0, pushBytes));
  buffers.emplace( std::string_view(data.begin(), data.begin() + pushBytes));

}

void Writer::close() noexcept
{

    is_closed_ = true;
  // Your code here.
}

bool Writer::is_closed() const noexcept
{
  return is_closed_; // Your code here.
}

uint64_t Writer::available_capacity() const noexcept
{
   // Your code here.

   return capacity_ - cur_bytes_buffered;
}

uint64_t Writer::bytes_pushed() const noexcept
{
  return tot_bytes_pushed_; // Your code here.
}

string_view Reader::peek() const noexcept
{
  if ( buffers.empty()) {
    return "";
  }

  return std::string_view{buffers.front().begin() + lazy_pointer, buffers.front().end()};
  // Your code here.
}

void Reader::pop( uint64_t len ) noexcept
{
  if ( 0 == len ) {
    return;
  }
  if ( buffers.empty()) {
    return;
  }
  
  while ( len > 0 && cur_bytes_buffered > 0) {
    std::string& s = buffers.front();
    
    auto real_sz = s.size() - lazy_pointer;
    auto pop_bytes = min( static_cast<uint64_t>( real_sz), len);
    if ( len >= real_sz ) {
      buffers.pop();
      lazy_pointer = 0;
    }
    else {
      lazy_pointer += pop_bytes;
        // s.erase(0, len);
    }
    
    len -= pop_bytes;
    cur_bytes_buffered -= pop_bytes;
    tot_bytes_poped_  += pop_bytes;
  }

 //  (void)len; // Your code here.
}

bool Reader::is_finished() const noexcept
{

  return is_closed_ && buffers.empty(); // Your code here.
}

uint64_t Reader::bytes_buffered() const noexcept
{
  return  cur_bytes_buffered; // Your code here.
}

uint64_t Reader::bytes_popped() const noexcept
{
  return tot_bytes_poped_; // Your code here.
}


  • bytestream.h
#pragma once

#include <cstdint>
#include <string>
#include <string_view>
#include <queue>
#include <algorithm>
#include <iostream>

class Reader;
class Writer;

class ByteStream
{
public:
  explicit ByteStream( uint64_t capacity );

  // Helper functions (provided) to access the ByteStream's Reader and Writer interfaces
  Reader& reader();
  const Reader& reader() const;
  Writer& writer();
  const Writer& writer() const;

  void set_error() noexcept{ error_ = true; };       // Signal that the stream suffered an error.
  bool has_error() const noexcept{ return error_; }; // Has the stream had an error?

protected:
  // Please add any additional state to the ByteStream here, and not to the Writer and Reader interfaces.
  uint64_t capacity_;
  bool error_ {};
  std::queue<std::string> buffers{};
  bool is_closed_{ false };

  uint64_t cur_bytes_buffered{};
  uint64_t tot_bytes_pushed_{};
  uint64_t tot_bytes_poped_{};

  size_t lazy_pointer{};
};

class Writer : public ByteStream
{
public:
  void push( std::string data ) noexcept; // Push data to stream, but only as much as available capacity allows.
  void close() noexcept;                  // Signal that the stream has reached its ending. Nothing more will be written.

  bool is_closed() const noexcept;              // Has the stream been closed?
  uint64_t available_capacity() const noexcept; // How many bytes can be pushed to the stream right now?
  uint64_t bytes_pushed() const noexcept;       // Total number of bytes cumulatively pushed to the stream
};

class Reader : public ByteStream
{
public:
  std::string_view peek() const noexcept; // Peek at the next bytes in the buffer
  void pop( uint64_t len ) noexcept;      // Remove `len` bytes from the buffer

  bool is_finished() const noexcept;        // Is the stream finished (closed and fully popped)?
  uint64_t bytes_buffered() const noexcept; // Number of bytes currently buffered (pushed and not popped)
  uint64_t bytes_popped() const noexcept;   // Total number of bytes cumulatively popped from stream
};

/*
 * read: A (provided) helper function thats peeks and pops up to `max_len` bytes
 * from a ByteStream Reader into a string;
 */
void read( Reader& reader, uint64_t max_len, std::string& out );


网站公告

今日签到

点亮在社区的每一天
去签到