• Http服务器实现文件上传与下载(五)


    一、引言

         欢迎大家和我一起编写Http服务器实现文件的上传和下载,现在我回顾一下在上一章节中提到的一些内容,之前我已经提到过文件的下载,在文件的下载中也提到了文件的续下载只需要在响应头中填写Content-Range这一字段,并且服务器的文件指针指向读取的指定位置开始读取传输。在这一章节中我讲讲解文件的上传这一功能,讲完这一章节,大致的功能也全部完成,接着就是上面文件控制模块和一些资源模块。

         在文件的上传中主要以HttpRequest类为主,在考虑文件的上传时我一点迷惑,到底把文件的上传功能是放到HttpResponse下还是在HttpRequest下,毕竟HttpResponse中有一些相应的文件下载功能,在添加一个文件上传功能也不为过。但是我最终还是选择在HttpRequest中,原因是我主要是HttpResponse作为是服务器到浏览器发送内容,而HttpRequest作为浏览器到服务器发送内容。这样下载和上传的功能就分别坐落在了HttpResponse和HttpRequest上了。

      在完成功能上的归属问题后,接着直接上代码,在文件的上传中,涉及到C++流。在这里其实用到不是很多的内容,但是这却是C++一个重要的一大块内容。有时间和大家在一起复习这一块内容。好了,接着上代码咯,上一章的内容有设计一些HttpRequest的代码,没有全部的包括进去。

    二、HttpRequest

    头文件(include/httprequest.h)

     1 #ifndef HTTPREQUEST_H
     2 #define HTTPREQUEST_H
     3 #include "socket.h"
     4 #include <map>
     5 #include <string>
     6 #include <fstream>
     7 namespace Http{
     8     class HttpRequest{
     9         public:
    10             HttpRequest(TCP::Socket &c);
    11             virtual ~HttpRequest();
    12             std::string getMethod() const;
    13             std::string getUrl()  const;
    14             std::string getHost() const;
    15             std::map<std::string,std::string>  getHeader(int confd) ;
    16             ssize_t upload(int confd,std::string filename);
    17         protected:
    18         private:
    19             std::string method;
    20             std::string url;
    21             std::string host;
    22             TCP::Socket &s;
    23     };
    24 }
    25 #endif // HTTPREQUEST_H

    源文件(src/httprequest.cpp)

     1 #include "httprequest.h"
     2 #include "utils.h"
     3 namespace Http{
     4     HttpRequest::HttpRequest(TCP::Socket &c):s(c){
     5     }
     6 
     7     HttpRequest::~HttpRequest(){
     8     }
     9     std::map<std::string,std::string> HttpRequest::getHeader(int confd){
    10         char recvBuf[1024];
    11         memset(recvBuf,0,sizeof(recvBuf));
    12         s.server_read(confd,recvBuf,1024);
    13         std::cout<<recvBuf<<std::endl;
    14         std::map<std::string,std::string> mp =Utils::parseHeader(recvBuf);
    15         method =mp["Method"];
    16         url=mp["Url"];
    17         host=mp["Host"];
    18         return mp;
    19     }
    20     ssize_t HttpRequest::upload(int confd,std::string filename){
    21         char buf[1024];
    22         size_t n=0;
    23         ssize_t  nread=0;
    24         std::string boundary;
    25         std::string file;
    26         std::ofstream outStream;
    27         int readlineCount=1;
    28         while(1){
    29             memset(buf,0,sizeof(buf));
    30             n=s.server_readline(confd,buf,sizeof(buf));
    31             if(readlineCount==1){
    32                 boundary=std::string(buf,buf+strlen(buf)-2);
    33                 boundary+="--
    ";
    34                 std::cout<<boundary<<std::endl<<boundary.size();
    35             }else if(readlineCount==2){
    36                 int i=n;
    37                 while(buf[i]!='='){
    38                     if((buf[i]>='0'&&buf[i]<='9')
    39                        ||(buf[i]>='a'&&buf[i]<='z')
    40                        ||(buf[i]>='A'&&buf[i]<='Z')
    41                        ||(buf[i]=='.'))
    42                     i--;
    43                     else{
    44                         buf[i]='*';
    45                         i--;
    46                     }
    47                 }
    48                 file=std::string(buf+i+2,buf+n-3);
    49             }else if(readlineCount==3){
    50                 std::string rw;
    51                 rw=std::string(buf,buf+strlen(buf));
    52                 int pos=rw.find('/');
    53                 rw=rw.substr(0,pos);
    54                 filename=filename+file;
    55                 if(rw=="Content-Type: text")
    56                     outStream.open(filename.c_str());
    57                 else{
    58                     outStream.open(filename.c_str(),std::ios::binary);
    59                     std::cout<<"ios::binary"<<std::endl;
    60                 }
    61             }else if(readlineCount==4){
    62                 memset(buf,0,sizeof(buf));
    63                 while(1){
    64                     n=s.server_readn(confd,buf,sizeof(buf));
    65                     if(n==boundary.size()&&strcmp(buf,boundary.c_str())==0){
    66                         goto exit;
    67                     }
    68                     nread+=n;
    69                     if(buf[n-1]==0){
    70                         outStream.write(buf,n-1);
    71                     }else{
    72                       outStream.write(buf,n);
    73                     }
    74                 }
    75             }
    76             readlineCount++;
    77         }
    78         exit:
    79         outStream.close();
    80         s.server_close(confd);
    81         return nread;
    82     }
    83     std::string HttpRequest::getMethod() const{
    84         return method;
    85     }
    86     std::string HttpRequest::getUrl()  const{
    87         return url;
    88     }
    89     std::string HttpRequest::getHost() const{
    90         return host;
    91     }
    92 }

         好了上传文件的代码也已经出来了,现在就是对其稍微的解释一下把。在解释代码之前先看一下我们在点击上传文件按钮的时候,浏览器给服务器发送的内容是什么,比如我有一个test.txt的文本文件(这里采用文件文件是为了好查看内容,其实二进制文件也是一致的)。test.txt文件的内容只有一行就是aaabbb这6个字母。接着打开可以火狐的开发者网络这一功能。并且点击发送文件后,可以在消息头上看到如下信息。

        这些内容在之前的章节已经讲过了,这里就不重复了,并且点击参数这一选项可以看到如下信息。

         在这里第1,2行是请求头的内容,接着一行空行之后是请求体4-9行。看到请求体的内容不是直接是test.txt的内容。显示‘--23469111452’为开头,拜师这个是文本的分隔符。前面固定一段'-',加上一个浏览器自动产生的数据。并且一个文件的解释也是这样,只是数字后面多了2个'-'。在第5,6行是对上传的文件的描述。接着是一行空行。第8行开始就是文件的内容了。知道这个请求体后,很容易的就可以写出代码。上面的的upload中readlineCount变量就是起到定位功能。看服务器已经接收到那一行了,这里s.server_readn这个行数之间没有提交,现在的代码段一直在修改,所以有些与博客有点差别,大体上还是一致的。

          写到这里,基本上完成了HttpServer这一文件上传和下载功能。接着就是组合这些某块。将在下一章《Http服务器实现文件上传与下载(六)》中进行讲解。

  • 相关阅读:
    什么,你还不会Mysql主从复制???快来看
    MySQL二进制安装(版本:5.7.26)
    MySQL--备份恢复【Mysqdump+xtrabackup(XBK)】
    Mysql日志分析(错误日志,Binlog日志,慢日志),有惊喜哦
    Mysql多实例启动
    Zabbix服务自定义监控和模板
    Centos7安装Zabbix服务端、Zabbix客户端和Win客户端配置(源码编译安装)
    运维工作经验汇总---------高级运维工程师
    手误【删库】 == 跑路,不存在的 ——删瓦辛格
    python——map()函数
  • 原文地址:https://www.cnblogs.com/liferecord/p/4866219.html
Copyright © 2020-2023  润新知