一、实验目的

1.初步了解计算机网络,准备实验所需的材料和环境;

2.掌握基础实验方法;

3.动手实现网络功能。

二、实验内容

1.下载实验所需的资料,安装虚拟机,配置环境;

2.获取一个网页;

3.监听和链接:尝试让自己的电脑变成一个简单的服务器,等待其他客户端连接;

4.使用套接字编写网络程序。

三、实验过程

(一)获取实验材料

电脑上已经安装过VMware虚拟机软件,无需再次下载;

在Ubuntu官网下载最新镜像。

(二)安装虚拟机

打开VMware,新建虚拟机

选择ubuntu64位

设置安装位置

为避免后期空间不足,适当加大磁盘大小

设置处理器

选择ISO镜像文件

安装

进行简单设置

稍作等待后安装成功

设置ubuntu管理员密码

安装vim

修改阿里云镜像

修改失败 使用图形化界面寻找最佳服务器

点击选择最佳服务器,进行测试

测试结束,选择该服务器

选择重新载入

安装cmake

安装g++

打开浏览器,访问http://cs144.keithw.org/hello

在终端中依次输入四条命令

telnet cs144.keithw.org http

GET /hello HTTP/1.1

Host: cs144.keithw.org

Connection: close

输入http://cs144.keithw.org/lab0/20212734

再次手动获取

监听和连接

按下crtl+c断开连接

安装git软件包

获取实验材料

进入目录

新建“build”目录

编译代码

在 build 目录中,使用编辑器打开 …/apps/webget.cc,将get_URL函数进行替换

测试程序

编写 …/src/byte_steam.cc 和 …/src/byte_steam.hh。在 .cc 文件中编写你的代码,在 .hh 文件中定义你的私有成员变量。(此处以.hh为例)

测试代码

实验结束。

四、实验体会

1.在本实验中,我通过获取一个网页,尝试让自己的电脑变成一个简单的服务器,等待其他客户端连接,我使用套接字编写了网络程序这些实验初步了解了计算机网络的实验实现,对计算机网络有了更加深入的了解;

2.在本实验中,我遇到的问题主要是在获取网页连续键入四条命令时总是超时,因为此处的服务器会因请求超时而关闭连接,只能通过粘贴方式输入。但我的虚拟机反复粘贴失败,最后查证是因为VMware Tools出现问题,重新安装后即可解决。

五、代码附录

byte_stream.cc

#include <stdexcept>

#include "byte_stream.hh"

using namespace std;

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

void Writer::push( string data ) noexcept
{
  auto len = min( data.size(), available_capacity() );  // 确定可写入的数据长度
  if ( len == 0 ) { // 如果可写入的数据长度为0,说明已经写满了,返回
    return;
  } else if ( len < data.size() ) { // 如果可写入的数据长度小于 data 的长度,说明只能写入部分数据
    data.resize( len );             // 将 data 的长度截断为可写入的长度
  }
  // 将 data 写入到 buffer 中
  buffer_data.push( move( data ) );
  if ( buffer_data.size() == 1)  // 写入前为空时需要更新 buffer_view
    buffer_view = buffer_data.front();
  // 更新已写入的数据长度
  bytes_pushed_ += len;
}

void Writer::close() noexcept
{
  flag |= ( 1 << CLOSED );
}

void Writer::set_error() noexcept
{
  flag |= ( 1 << ERROR );
}

bool Writer::is_closed() const noexcept
{
  return flag & ( 1 << CLOSED );
}

uint64_t Writer::available_capacity() const noexcept
{
  return capacity_ - reader().bytes_buffered();
}

uint64_t Writer::bytes_pushed() const noexcept
{
  return bytes_pushed_;
}

string_view Reader::peek() const noexcept
{
  return buffer_view;
}

bool Reader::is_finished() const noexcept
{
  return writer().is_closed() && ( bytes_buffered() == 0 );
}

bool Reader::has_error() const noexcept
{
  return flag & ( 1 << ERROR );
}

void Reader::pop( uint64_t len ) noexcept
{
  if ( len > bytes_buffered() ) {
    return;
  }
  // 更新已弹出的数据长度
  bytes_popped_ += len;

  // 将 buffer 中的数据弹出
  while ( len > 0 ) {
    if ( len >= buffer_view.size() ) {
      len -= buffer_view.size();
      buffer_data.pop();
      buffer_view = buffer_data.front(); // 最开始就保证了 buffer_data 不为空
    } else {
      buffer_view.remove_prefix( len );
      len = 0;
    }
  }
}

uint64_t Reader::bytes_buffered() const noexcept
{
  return writer().bytes_pushed() - bytes_popped();
}

uint64_t Reader::bytes_popped() const noexcept
{
  return bytes_popped_;
}

Byte_stream.hh

// byte_stream.hh
#pragma once
#include <cstdint>
#include <queue>
#include <stdexcept>
#include <string>
#include <string_view>

using std::uint64_t;

class Reader;
class Writer;

class ByteStream
{
protected:
  enum State { CLOSED, ERROR };
  uint64_t capacity_;
  uint64_t bytes_pushed_ {}; // 已写入的字节数
  uint64_t bytes_popped_ {}; // 已弹出的字节数

  unsigned char flag {};        // 0: normal, 1: closed, 2: error
  std::queue<std::string> buffer_data {};
  std::string_view buffer_view {};

public:
  explicit ByteStream( uint64_t capacity );

  // 提供ByteStream的 reader 和 writer 接口的辅助函数
  Reader& reader();
  const Reader& reader() const;
  Writer& writer();
  const Writer& writer() const;
};

class Writer : public ByteStream
{
public:
  void push( std::string data ) noexcept; // 在可用容量允许的范围内向流中写入数据

  void close() noexcept; // 关闭流,不允许再向流中写入数据
  void set_error() noexcept; // 流中出现错误,置位错误标志

  bool is_closed() const noexcept;      // 判断流是否已关闭
  uint64_t available_capacity() const noexcept; // 计算流中剩余可用容量
  uint64_t bytes_pushed() const noexcept;       // 计算流中已写入的字节数
};

class Reader : public ByteStream
{
public:
  std::string_view peek() const noexcept; // 返回流中下一个数据块的只读视图
  void pop( uint64_t len ) noexcept;      // 从流中弹出指定长度的数据块

  bool is_finished() const noexcept; // 判断流是否已关闭且所有数据块都已弹出
  bool has_error() const noexcept;   // 判断流是否出现错误

  uint64_t bytes_buffered() const noexcept; // 计算当前流中剩余的字节数
  uint64_t bytes_popped() const noexcept;   // 计算流中已弹出的字节数
};

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

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐