电竞比分网-中国电竞赛事及体育赛事平台

分享

Http服務器實現(xiàn)文件上傳與下載(五)

 LibraryPKU 2017-03-17

一、引言

     歡迎大家和我一起編寫Http服務器實現(xiàn)文件的上傳和下載,現(xiàn)在我回顧一下在上一章節(jié)中提到的一些內容,之前我已經(jīng)提到過文件的下載,在文件的下載中也提到了文件的續(xù)下載只需要在響應頭中填寫Content-Range這一字段,并且服務器的文件指針指向讀取的指定位置開始讀取傳輸。在這一章節(jié)中我講講解文件的上傳這一功能,講完這一章節(jié),大致的功能也全部完成,接著就是上面文件控制模塊和一些資源模塊。

     在文件的上傳中主要以HttpRequest類為主,在考慮文件的上傳時我一點迷惑,到底把文件的上傳功能是放到HttpResponse下還是在HttpRequest下,畢竟HttpResponse中有一些相應的文件下載功能,在添加一個文件上傳功能也不為過。但是我最終還是選擇在HttpRequest中,原因是我主要是HttpResponse作為是服務器到瀏覽器發(fā)送內容,而HttpRequest作為瀏覽器到服務器發(fā)送內容。這樣下載和上傳的功能就分別坐落在了HttpResponse和HttpRequest上了。

  在完成功能上的歸屬問題后,接著直接上代碼,在文件的上傳中,涉及到C++流。在這里其實用到不是很多的內容,但是這卻是C++一個重要的一大塊內容。有時間和大家在一起復習這一塊內容。好了,接著上代碼咯,上一章的內容有設計一些HttpRequest的代碼,沒有全部的包括進去。

二、HttpRequest

頭文件(include/httprequest.h)

復制代碼
 1 #ifndef HTTPREQUEST_H
 2 #define HTTPREQUEST_H
 3 #include "socket.h"
 4 #include 
 5 #include <string>
 6 #include 
 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<>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<>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<<>std::endl;
14         std::map<>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+="--\r\n";
34                 std::cout<<><>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 }<>
復制代碼

     好了上傳文件的代碼也已經(jīng)出來了,現(xiàn)在就是對其稍微的解釋一下把。在解釋代碼之前先看一下我們在點擊上傳文件按鈕的時候,瀏覽器給服務器發(fā)送的內容是什么,比如我有一個test.txt的文本文件(這里采用文件文件是為了好查看內容,其實二進制文件也是一致的)。test.txt文件的內容只有一行就是aaabbb這6個字母。接著打開可以火狐的開發(fā)者網(wǎng)絡這一功能。并且點擊發(fā)送文件后,可以在消息頭上看到如下信息。

    這些內容在之前的章節(jié)已經(jīng)講過了,這里就不重復了,并且點擊參數(shù)這一選項可以看到如下信息。

     在這里第1,2行是請求頭的內容,接著一行空行之后是請求體4-9行??吹秸埱篌w的內容不是直接是test.txt的內容。顯示‘--23469111452’為開頭,拜師這個是文本的分隔符。前面固定一段'-',加上一個瀏覽器自動產(chǎn)生的數(shù)據(jù)。并且一個文件的解釋也是這樣,只是數(shù)字后面多了2個'-'。在第5,6行是對上傳的文件的描述。接著是一行空行。第8行開始就是文件的內容了。知道這個請求體后,很容易的就可以寫出代碼。上面的的upload中readlineCount變量就是起到定位功能??捶掌饕呀?jīng)接收到那一行了,這里s.server_readn這個行數(shù)之間沒有提交,現(xiàn)在的代碼段一直在修改,所以有些與博客有點差別,大體上還是一致的。

      寫到這里,基本上完成了HttpServer這一文件上傳和下載功能。接著就是組合這些某塊。將在下一章《Http服務器實現(xiàn)文件上傳與下載(六)》中進行講解。

 

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多