⚡通信管理模块⚡

news2025/1/10 12:09:32

目录

🌳.通信管理模块的介绍

🌳.通信模块的设计

🌳.ListShow函数

🌳.UpLoad函数

🌳.DownLoad函数

下载的断点续传


🌳.通信管理模块的介绍

通信管理模块管理着服务器与浏览器之间的通信:

  • 当服务器收到浏览器的 get /listshow/ http/1.1请求时,服务器就会給浏览器响应一个文件展示页面,用户可以再这个页面上传文件或下载文件。
  • 当服务器收到浏览器的 个 get /download/文件名 http1.1请求时,服务器就会到backdir目录下或
  • packdir目录下查找该文件,如果找到了,就将该文件发送給浏览器。
  • 当服务器收到浏览器的 个post /upload/ http1.1请求时,则浏览器将文件上传到服务器上,文件名和文件数据存储在http响应中,服务器则将该文件放入backdir目录下。

🌳.通信模块的设计

将通信模块设计为单例模式,保证系统中只有一个通信模块对象.

服务器在运行的时候,先注册各个请求与对应函数的关心

   class Service{
      private:
        std::string ip;
        int port;
        httplib::Server server;
        static std::mutex lock;
        static Service* instant;
      private:
        Service(){
          ip=sjp::Config::GetInstant()->GetIp();
          port=sjp::Config::GetInstant()->GetServerPort();
        }
  
        Service(Service&)=delete;
        static std::string mtimeToString(time_t mtime){
          std::string res= ctime(&mtime);
          return res;
        }
      public:
        void Run(){
          server.Post("/upload",UpLoad); 
          server.Get("/download/(.*)",DownLoad);
          server.Get("/listshow",ListShow);                                                                                                                                                 
          server.Get("/",ListShow);
          server.listen("0.0.0.0",port);//启动服务器
        }

      static Service* GetInstant(){
          if(instant==nullptr){
            lock.lock();
            if(instant==nullptr){
              instant=new Service();
            }
            lock.unlock();
          }
          return instant;
        }
    };
  
    std::mutex Service::lock;
    Service* Service::instant=nullptr;
  }                                                              

🌳.ListShow函数

  listshow页面的前端源代码如下:

  •  我们需要使用stringstream对象将前端页面的源代码组织起来,然后将在将stringstream组织在http响应中,httplib服务器在底层会将http响应发送給浏览器。
  • 为了保证浏览器能够将前端代码翻译成一个页面,需要在httplib响应中的Content-type字段设置为text/html.
static void ListShow(const httplib::Request& req,httplib::Response& rep){    
          cout<<"listshow"<<endl;    
          std::vector<sjp::FileInfo> arry;    
          sjp::FileInfoManger::GetInstant()->GetAllInfo(arry);    
          std::stringstream ss;    
      
          //    
          ss<<"<!DOCTYPE html>"<<"<html><meta charset=\"UTF-8\"><head><title>Download</title></head><body><h1>Download</h1><table>";      
                        ss<<"<tr><td><h3>文件名</h3></a></td>";        
          ss<<"<td align=\"left\">"<<"<h3>最近修改时间</h3>"<<"</td>";                                                 
          ss<<"<td align=\"right\">"<<"<h3>文件大小</h3>"<<"</td></tr>";     
W>        for(int i=0;i<arry.size();i++){    
            //>    
            /*<td><a href="/download/test.txt">test.txt</a></td>    
              <td align="right">2021-12-29 10:10:10</td>    
              <td align="right">28k</td>    
             * */    
            std::string path=arry[i].back_path;    
            sjp::FileUtil fu(path);    
            std::string atimestr=mtimeToString(arry[i].modify_time);    
            ss<<"<tr><td><a href=\"/download/"<<fu.GetFilename()<<"\">"<<fu.GetFilename()<<"</a></td>";    
            ss<<"<td align=\"right\">"<<atimestr<<"    </td>";    
            ss<<"<td align=\"right\">"<<arry[i].file_size/1024<<"k"<<"</td></tr>";                                                                                                          
          }    
          ss<<"</table></body></html>";
          ss<<"<form action=\"http://119.23.41.13:8081/upload\" method=\"post\" enctype=\"multipart/form-data\"><div><input type=\"file\" name=\"file\"></div><div><input type=\"submit\" va  lue=\"上传\"></div></form>";
          rep.body=ss.str();
          rep.status=200;
          rep.set_header("Content-Type","text/html;");
        }
  

🌳.UpLoad函数

post /upload/ http1.1请求如下

上传文件的请求中请求正文包含文件的字段名和文件名,文件正文(文件包含的数据)。

实现:

  • 服务器收到上传请求后,需要先判断是否有文件字段名,如果有则提取该文件的信息。
  • 然后使用FileUtil文件工具打开一个文件存放在backdir下,并将文件正文写入到该文件中,并新插入一个文件信息到文件管理系统中_table表中,则完成服务器上传文件的请求。
  • 重新返回一个文件页面。
        static void UpLoad(const httplib::Request& req,httplib::Response& rep)
        {
          /* 1.判断是否有文件上传
           * 2.如果有,则获取该文件的名称和内容
           * 3.在backdir中创建一个文件
           * 4.将文件信息存储到FileInfoManger中
           * */
          //判断是否有文件上传
          std::cout<<"upload begin"<<endl;
            auto res=req.has_file("file");
            if(res==false){
              rep.status=400;                                                                                                                                                               
              return;
            } 
          const auto& file=req.get_file_value("file");
            std::string filepath=sjp::Config::GetInstant()->GetBackDir()+file.filename;
            std::string body=file.content;
  
            sjp::FileUtil fu(filepath);
            fu.SetContent(body);
  
            sjp::FileInfo fileinfo(filepath);
            sjp::FileInfoManger::GetInstant()->Insert(fileinfo);  
            sjp::FileInfoManger::GetInstant()->Storage();
            ListShow(req,rep);
        }
  

🌳.DownLoad函数

  • 当服务器收到一个下载请求时,服务器需要执行的步骤:
  • 文件信息管理模块通过请求url获取该文件信息,如果没有该文件信息,则说明该文件不存在,返回404.
  • 如果存在该文件,则通过文件信息中的packsign判断是否被压缩
  • 如果packsign=false,说明该文件没有没有被压缩,则服务器直接从backdir目录下将获取文件内容发送給浏览器。
  • 如果packsign=true,说明该文件已经被压缩,则服务器从packdir目录下将该文件进行解压缩到backdir,并删除packdir目录下的压缩包,将文件信息中的packsign修改为false,最后将文件内容发送給浏览器。
  • 如果浏览器想要以下载的形式接受文件,则服务器需要将http响应中的Content-Type字段设置为application/octet-stream

下载的断点续传

用户在下载文件的过程中,可能因为网络或者其它原因导致服务器下载失败了,如果没有断点续传,则用户重新下载文件则需要从文件的最开始的位置下载,如果实现了断点续传,则用户重新下载 文件则会从上次失败的位置开始下载

http下载的断点续传的思想

当浏览器第一次下载的时候,服务器給浏览器发送的http响应添加Accept-Ranges和Etag这两个字段:

  • Accept-Ranges一般被设置为bytes ,表示这个字段表示服务器支持断点续传,以字节为单位传输数据.
  • ETag表示的是服务器上某一版本资源的唯一标识,如果资源被改动过,则ETag会改变,客户端收到后则会保证这个信息。

如果下载中断了,浏览器重新下载文件,则第二次的http请求中需要包含If-Range字段和Range字段.

  • If-Range字段:"保存服务端的响应的ETag字段的信息",用于判断与服务端中与上一次请求资源是否一致,如果一致则断点续传,如果不一致,则重新开始下载。
  • Range字段:bytes start-end,表示的是请求服务器资源从start个字节开始到end个字节结束的数据。

则服务端发送http响应給客户端需要包含Content-Range字段和ETag字段:

  • Content-Range:start-end/文件大小,表示http响应包含文件数据从start开始到end结束的文件数据,文件大小表示文件总大小。
  • ETag:表示的是服务器上资源的唯一标识。

ETag字段的设定

ETag某一版本资源的唯一标识,如果资源被改动过,则ETag则会改变,所以我们可以通过"文件名-文件大小-文件修改时间"来设定ETag(当然这不是唯一的方式)。

UpDown函数的实现

如果浏览器发生断点续传请求,则在httplib内部实现了对Range字段的解析,开发人员只需要读取文件中的内容,设定好字段,底层的httplib库则会自动定位好具体的数据范围,发送給浏览器。


        
      //文件名-文件大小-最后一次修改时间
        static  std::string GetEtag(std::string filename){
           sjp::FileUtil fu(filename);
           std::string etag=fu.GetFilename();
           etag+="-";
           etag+=std::to_string(fu.GetFileSize());
           etag+="-";
           etag+=std::to_string(fu.GetFileModfityTime());
           return etag;
        }
  

     static void DownLoad(const httplib::Request& req,httplib::Response& rep)
        {
 
          cout<<"download begin"<<endl;
          std::string url=req.path;
          sjp::FileInfo fileinfo;
          sjp::FileInfoManger::GetInstant()->GetoneByURL(url,fileinfo);                                

         if(!sjp::FileInfoManger::GetInstant()->Exist(fileinfo.back_path)){
            /* sjp::FileUtil fu(back_dir); 
             std::vector<std::string> arry;
             fu.GetPathInDir(arry);
             */
            rep.status=404;
            return ;
          }
  
          if(fileinfo.pack_sign==true)
          {
            //解压缩
            sjp::FileUtil fu(fileinfo.pack_path);
            fu.UnpackFile(fileinfo.back_path);
            fileinfo.pack_sign=false;
            sjp::FileInfoManger::GetInstant()->Insert(fileinfo);
            fu.Remove();
          }
  
  
          bool flag=false;
          //判断是否为断点续传
          if(req.has_header("If-Range")){
            //断点续传
            std::string oldetag=req.get_header_value("If-Range"); 
            if(oldetag==GetEtag(fileinfo.back_path)){
               //需要断点续传
               cout<<"oldetag: "<<oldetag<<endl;
               cout<<"etag: "<<GetEtag(fileinfo.back_path)<<endl;                                                                                                                           
               flag=true;
            }
          }
         sjp::FileUtil fu(fileinfo.back_path);
          //获取文件内容
          std::string body;
          fu.GetContent(body);
          rep.body=body;
          rep.content_length_=body.size();
          if(flag==false){
          //不需要断点续传
           rep.status=200;
           rep.set_header("Accept-Ranges","bytes");
           rep.set_header("Content-Type","application/octet-stream");
           rep.set_header("Etag",GetEtag(fileinfo.back_path));
          }
          else{
            //断点续传
            rep.status=206;
            rep.set_header("Accept-Ranges","bytes");
            rep.set_header("Content-Type","application/octet-stream");
            rep.set_header("ETag",GetEtag(fileinfo.back_path));
          }
          return ;
        }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/75442.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

猿如意工具-【SwitchHosts】详情介绍

一、什么是猿如意&#xff1f; 在发表文章的契机下&#xff0c;看到了【猿如意】这个名词。处于好奇&#xff0c;点击进行了解。 发现是我们熟悉的CSDN提供的一个面向开发者的辅助开发工具箱&#xff0c;猿如意的意思是-程序猿&#xff08;员&#xff09;的如意兵器。 它提供…

Elasticsearch与spring data整合api变化

记录 spring-data-elasticsearch 版本api变化 https://blog.csdn.net/zlpzlpzyd/article/details/128255792 spring boot 2.7.x 对应 spring-data-elasticsearch 4.4.x 排查问题之前先看一下上述链接中版本的对应关系 org.springframework.data.elasticsearch.core.Elastics…

如何搭建真实的性能测试环境?

在编写脚本的同时&#xff0c;执行场景之前需要完成测试环境的搭建工作&#xff0c;这里包括硬件和软件环境的搭建。根据性能测试计划中的测试环境规划&#xff0c;完成对整个测试环境的搭建。由于性能测试的特殊性&#xff0c;整个测试环境需要在严格的独立监控下管理&#xf…

微信建群怎么建?2个方法,快速学会!

​如果你想建立一个微信群来提高工作效率&#xff0c;你该怎么办&#xff1f;微信建群怎么建&#xff0c;找了很长一段时间不到。下面小编分享2个微信建群的方法&#xff0c;可以让您快速学习如何建立微信群&#xff01;感兴趣的小伙伴可以来看看哦&#xff01; 微信建群方法一…

JDBC第一章节(从概念到操作)

一、数据持久化存储回顾 1、持久化概述 2. JAVA中的数据存储 二、JDBC概述 1.概述 1.1 概述&#xff1a; 1.2 没有jdbc之前存在一些问题 1.3 有jdbc 之后 1.4 JDBC本质 1.5 优点 三、JDBC API 四、初始JDBC 操作数据库 1、操作步骤概述 2、实操步骤 2.1 导入MySQ…

Vue 实现拖拽模块(三)自定义拖拽组件的样式

上文介绍了 自定义拖拽组件位置 的简单实现&#xff0c;本文将继续给大家分享如何自定义拖拽组件位置的简单实现&#xff0c;文中通过示例代码介绍&#xff0c;感兴趣的小伙伴们可以了解一下 本文主要介绍了 Vue 自定义拖拽组件的样式&#xff0c;具体如下&#xff1a; 支持通过…

番外-LogParser(IIS日志分析)

编写原因&#xff1a;在线的那个信息管理系统&#xff0c;总有人添加空白数据&#xff0c;一加就是很多条&#xff0c;用这个分析一下&#xff0c;再发现之后将其IP拉入黑名单 1&#xff0c;下载安装 网盘下载链接 提取码&#xff1a;229e 文件下载后解压&#xff0c;解压后为…

Lecture5:卷积层、池化层、全连接层

目录 1.卷积层、池化层、全连接层 1.1 全连接层 1.2 卷积层 1.3 池化层 1.卷积层、池化层、全连接层 1.1 全连接层 对全连接层而言&#xff0c;我们要做的就是在这些向量上进行操作&#xff0c;比如我们有一张RGB-D图片&#xff0c;它的大小为32*32*3&#xff0c;我们将所…

vue3 几款值得推荐的UI组件库

推荐几个比较流行的VUE3 UI框架&#xff0c;同时提供出色的开发人员体验&#xff0c;合理利用&#xff0c;又或者学习借鉴都是不错的选择&#xff0c;排名不分先后。 Ant Design Vue 官方网站&#xff1a;https://2x.antdv.com/components/overview/ Ant Design Vue 是一个非…

PingCAP 成为中国唯一入选 Forrester Wave 数据库厂商,被评为卓越表现者

2022 年 12 月 6 日&#xff0c;国际权威研究机构 Forrester 发布了「Forrester Wave™: Translytical Data Platforms, Q4 2022 」报告&#xff0c;企业级开源分布式数据库厂商 PingCAP 作为中国唯一入围的数据库厂商&#xff0c;首次参评该报告即获评“卓越表现者&#xff08…

微服务框架 SpringCloud微服务架构 29 ES 集群 29.3 集群职责及脑裂

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构29 ES 集群29.3 集群职责及脑裂29.3.1 ES 集群的节点角色29.3.2 ES集群的分…

RAID图解

RAID图解什么是RAID各种 RAID 详解RAID 0RAID 1RAID 2&#xff08;已淘汰&#xff09;RAID 3RAID 4RAID 5RAID 6RAID 7RAID 01RAID 10RAID 10和RAID 01有何区别&#xff1f;实操教程其他问题最近在涉及到服务器安装系统这块才了解到RAID这个知识点&#xff0c;上网了解该知识&a…

Nginx 动静分离相关配置解析

Nginx 动静分离相关配置解析 本篇主要介绍nginx 动静分离相关配置解析 概述 动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来&#xff0c;动静资源做好了拆分以后&#xff0c;我们就可以根据静态资源的特点将其做缓存操作&#xff0c;这就是…

基于jsp+mysql+ssm智慧仓库进销存系统-计算机毕业设计

项目介绍 企业仓库库存系统的设计在SSM的框架下&#xff0c;采用JAVA编程语言和JSP技术&#xff0c;&#xff0c;并使用Mysql作为系统的数据库。该系统设计了强大的功能模块&#xff0c;考虑了企业库存管理的各个方面。这些主要功能模块分别是系统用户管理、用户信息管理、商品…

CUDNN与CUDA的踩坑与记录

CUDNN与CUDA的踩坑与记录 CUDA的安装 nvidia-smi看显卡驱动能够安装的最高版本的CUDA下载CUDA–>点击安装过程去掉显卡驱动安装完成的结果如下&#xff1a;Summary Driver: Not Selected Toolkit: Installed in /usr/local/cuda-10.2/ Samples: Installed in /home/g…

【世界杯中的安全思考】工控设备

目录 1、总述 2、半自动越位技术&#xff1a;人工智能辅助裁判 3、卡塔尔的智能道路 4、体育场的冷却技术 5、医疗援助的可穿戴设备 6、实时导航 7、照明系统 8、感官观察室 1、总述 从世界杯带来的科技感&#xff0c;可以看出大到球场&#xff0c;小到足球&#xff0c;…

厨房装修竟然有这么多你不知道的事

每个家庭的厨房大小、形状不同&#xff0c;厨房的建筑结构在房子中往往也是比较复杂的&#xff0c;橱柜等设施如何安置&#xff0c;都要因地制宜&#xff0c;很难说怎样做最好。但这并不意味着厨房的布局没有规律可循。在规划厨房布局时&#xff0c;最简单的办法就是按照做饭的…

微服务框架 SpringCloud微服务架构 29 ES 集群 29.1 集群结构介绍

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构29 ES 集群29.1 集群结构介绍29.1.1 ES集群结构29 ES 集群 29.1 集群结构…

银行软件测试简历模板,找工作的小伙伴看过来了

目录 个人简历 教育背景 工作经历 自我评价 专业技能 总结 重点&#xff1a;配套学习资料和视频教学 个人简历 姓  名&#xff1a; 性  别&#xff1a; 学  历&#xff1a; 经  验&#xff1a; 手  机&#xff1a; 邮  箱&#xff1a; 政治面貌&#…

水滴公司Q3财报引股价增长,保险业复苏“第一枪”打响了?

2020年以来&#xff0c;保险行业整体都笼罩在发展失速的低迷中。 2020年&#xff0c;在保险中介监管信息系统执业登记的保险销售从业人员有971.2万人&#xff0c;而2022年6月&#xff0c;这项数据为570.7万人&#xff0c;接近腰斩。公开数据显示&#xff0c;2022前三季度&…