自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Http服務(wù)器實(shí)現(xiàn)文件上傳與下載(四)

網(wǎng)絡(luò) 網(wǎng)絡(luò)管理
歡迎大家來到和我一起編寫Http服務(wù)器實(shí)現(xiàn)文件的上傳和下載,現(xiàn)在我稍微回顧一下之前我說的,第一、二章說明說明了整體的HTTP走向,第三章實(shí)現(xiàn)底層的網(wǎng)絡(luò)編程。接著這一章我想給大家講的是請求獲取,和響應(yīng)發(fā)送的內(nèi)容。這里主要講解的響應(yīng)內(nèi)容,為什么?因?yàn)槲覀兙帉懙氖且粋€(gè)與瀏覽器交互的HTTP服務(wù)器,所以大多數(shù)的情況下我們只進(jìn)行被動(dòng)的應(yīng)答。

一、引言

歡迎大家來到和我一起編寫Http服務(wù)器實(shí)現(xiàn)文件的上傳和下載,現(xiàn)在我稍微回顧一下之前我說的,***、二章說明說明了整體的HTTP走向,第三章實(shí)現(xiàn)底層的網(wǎng)絡(luò)編程。接著這一章我想給大家講的是請求獲取,和響應(yīng)發(fā)送的內(nèi)容。這里主要講解的響應(yīng)內(nèi)容,為什么?因?yàn)槲覀兙帉懙氖且粋€(gè)與瀏覽器交互的HTTP服務(wù)器,所以大多數(shù)的情況下我們只進(jìn)行被動(dòng)的應(yīng)答。

這就是一種"提問--回答"的問題。其實(shí)在講解這章的時(shí)候,我本來準(zhǔn)備給大家講解一下Linux一些信號中斷的問題。因?yàn)樵诰W(wǎng)絡(luò)層發(fā)送的時(shí)候,系統(tǒng)會(huì)發(fā)送一些信號給我們的應(yīng)用程序,所以會(huì)導(dǎo)致我們的程序意外的終止。但當(dāng)我寫的這篇博客的時(shí)候我又放棄,我想在講流程走向的時(shí)候再提一個(gè)中斷捕獲吧。在這個(gè)請求響應(yīng)層的類其實(shí)真正的設(shè)計(jì)需要很多的內(nèi)容,這里就是HttpResponse類和HttpRequest類的設(shè)計(jì),在j2EE中,我們編寫Servlet的時(shí)候就用到了這2個(gè)類,如HttpServletResquest,HttpServletResponse的類,如果對這里面的內(nèi)容感興趣,可以下載tomcat,在servlet-api.jar包里面有這些類。

在本文的實(shí)現(xiàn)中,Request類只包含了一個(gè)獲取請求頭和解析頭的一些方法。如何解析頭,我在《Http服務(wù)器實(shí)現(xiàn)文件上傳與下載(一)》已經(jīng)講解了,讀者只需要對其封裝一個(gè)類即可。

二、HttpRequest類

請求消息的解析是通過被定義在命名空間為Http的類名為HttpRequest。這個(gè)類的構(gòu)造函數(shù)接受一個(gè)套接字,就是跟我們連接的那個(gè)套接字,在網(wǎng)絡(luò)層我們已經(jīng)講過了,然后在getHeader方法中調(diào)用server_read()獲取請求頭,然后通過Utils::parseHeader()函數(shù)進(jìn)行解析。這樣把解析的內(nèi)容放入需要的string中,當(dāng)前不太需要的直接在map里面。這里我直接貼出代碼,大家看起來也比較容易。這里我在這一章節(jié)我主要講解的是文件的下載,所以主要會(huì)對HttpResponse的類的分析,而HttpRequest類只貼出目前需要的內(nèi)容。

頭文件(include/httprequest.h)

 

1 #ifndef HTTPREQUEST_H
2 #define HTTPREQUEST_H
3 #include "socket.h"
4 #include 
5 #include 
6 #include 
7 namespace Http{
8 class HttpRequest{
9 public:
10 HttpRequest(TCP::Socket &c);
11 virtual ~HttpRequest();
12 std::map
13 ......
14 protected:
15 private:
16 std::string method;
17 std::string url;
18 std::string host;
19 TCP::Socket &s;
20 };
21 }
22
23 #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
10 char recvBuf[1024];
11 memset(recvBuf,0,sizeof(recvBuf));
12 s.server_read(confd,recvBuf,1024);
13 std::cout<
14 std::map
15 method =mp["Method"];
16 url=mp["Url"];
17 host=mp["Host"];
18 return mp;
19 }
20 ......
21 }

 

三、HttpResponse類

當(dāng)我們訪問Http服務(wù)器的時(shí)候,瀏覽器顯示可以下載的文件的內(nèi)容,然后我們點(diǎn)擊需要下載的文件,然后文件就可下載了。首先我點(diǎn)擊這個(gè)文件這個(gè)URL時(shí),瀏覽器給我們發(fā)送一些請求頭,例如它發(fā)送一個(gè)為/download/HttpServer.zip這個(gè)URL,說明他需要下載的文件,而且該文件為HttpServer.zip。在上面我們已經(jīng)可以用getHeader來捕獲這個(gè)請求頭,然后獲取這個(gè)URL。之后服務(wù)端還是要發(fā)送一個(gè)響應(yīng)頭,告訴瀏覽器你的請求我們同意,請求頭結(jié)束以空行為標(biāo)記,接著就是具體的文件的內(nèi)容了。

在發(fā)送響應(yīng)頭時(shí),還是需要發(fā)送協(xié)議版本,狀態(tài)碼,響應(yīng)內(nèi)容類型,文件的長度,文件斷點(diǎn)下載等內(nèi)容,或者傳輸?shù)臅r(shí)候采用chunk傳輸,但是這里我采用文件的長度來標(biāo)記。讀者可以自行查看其它方式傳輸內(nèi)容。特別要注意ed是一定要在響應(yīng)頭中指定傳輸實(shí)體的大小,否則客戶端不知道什么時(shí)候結(jié)束,這時(shí)可能拒絕接收服務(wù)端發(fā)來的字節(jié)。在這個(gè)類中,請求下載的文件發(fā)送時(shí),我采用sendFile這個(gè)函數(shù),這個(gè)函數(shù)讀取文件就是采用二進(jìn)制的方式,并且在響應(yīng)頭中也告知瀏覽器以二進(jìn)制的方式接收文件。這樣都是以二進(jìn)制的方式讀取和發(fā)送文件才不會(huì)出現(xiàn)問題。sendLineFile 和sendIndexFile兩者大致相同,都是采用ASCII文本的方式發(fā)送內(nèi)容,這樣比如HTML這些需要顯示在瀏覽器的內(nèi)容,可以通過這兩個(gè)函數(shù)。通過函數(shù)名可知在sendLineFile會(huì)以文件行的方式讀取,而sendIndexFile文件會(huì)把內(nèi)容寫在同一行上。例如:我們?yōu)g覽器請求一個(gè)index.html的內(nèi)容,這時(shí)采用2個(gè)sendLineFile和sendIndexFile的顯示效果都是一樣的,但是如果點(diǎn)擊右鍵查看源碼時(shí),sendLineFile的內(nèi)容是以源文件一樣的,而sendIndexFile發(fā)送的內(nèi)容會(huì)都在***行,不會(huì)換行。

說了這么多大家也比較清楚了,下面貼出具體一些代碼。

頭文件(include/httpresponse.h)

 

1 #ifndef HTTPRESPONSE_H
2 #define HTTPRESPONSE_H
3 #include "socket.h"
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include "utils.h"
11 namespace Http{
12 class HttpResponse{
13 public:
14 HttpResponse(TCP::Socket &c);
15 virtual ~HttpResponse();
16 ssize_t send(int confd,std::string content);
17 ssize_t sendIndexFile(int confd,std::string FileName);
18 ssize_t sendFile(int &confd,std::string FileName,int64_t pos);
19 ssize_t sendLineFile(int confd,std::string file);
20 void setProtocal(std::string);
21 void setStatusCode(std::string);
22 void setServerName(std::string);
23 void setContentType(std::string);
24 void setContentRange(std::string);
25 void setContentLength(int64_t);
26 protected:
27 std::string getHeader() const;
28 private:
29 std::string protocal;
30 std::string statusCode;
31 std::string serverName;
32 std::string contentType;
33 std::string contentLength;
34 std::string contentRange;
35 std::string connection;
36 std::string date;
37 TCP::Socket &s;
38 };
39 }
40 #endif // HTTPRESPONSE_H

 

#p#

源文件(src/httpresponse.cpp)

 

1 #include "httpresponse.h"
2 namespace Http{
3 HttpResponse::HttpResponse(TCP::Socket &c):s(c){
4 protocal="HTTP/1.1";
5 statusCode="200 OK";
6 serverName="Server:(Unix)";
7 contentType="Content-type:text/html";
8 contentLength="Content-length:0";
9 contentRange="Content-Range:0-";
10 connection="Connection:Keep-Alive";
11 time_t timep;
12 time(&timep);
13 char s[50];
14 sprintf(s,ctime(&timep));
15 date="Date:"+std::string(s,s+(strlen(s)-1));
16 }
17
18 HttpResponse::~HttpResponse(){
19 }
20 void HttpResponse::setProtocal(std::string content){
21 protocal=content;
22 }
23 void HttpResponse::setStatusCode(std::string content){
24 statusCode=content;
25 }
26 void HttpResponse::setServerName(std::string content){
27 serverName=content;
28 }
29 void HttpResponse::setContentType(std::string content){
30 contentType="Content-type:"+content;
31 }
32 void HttpResponse::setContentLength(int64_t len){
33 contentLength="Content-length:"+Utils::toString(len);
34 }
35 void HttpResponse::setContentRange(std::string content){
36 contentRange="Content-Range:"+content;
37 }
38 std::string HttpResponse::getHeader() const{
39 std::string h1 =protocal+" "+statusCode+"\r\n";
40 std::string h2 =serverName+"\r\n";
41 std::string h3 =contentType+"\r\n";
42 std::string h4 =contentLength+"\r\n";
43 std::string h5=contentRange+"\r\n";
44 std::string h6=connection+"\r\n";
45 std::string h7=date+"\r\n\r\n";
46 return h1+h2+h3+h4+h5+h6+h7;
47 }
48 ssize_t HttpResponse::send(int confd,std::string content){
49 setContentType("application/octet-stream");
50 setContentLength(content.size());
51 std::string header=getHeader();
52 s.server_write(confd,(char*)header.c_str(),header.size());
53 ssize_t len =s.server_write(confd,(char*)content.c_str(),content.size());
54 s.server_close(confd);
55 return len;
56 }
57 ssize_t HttpResponse::sendLineFile(int confd,std::string file){
58 std::ifstream in(file.c_str());
59 in.seekg(0,std::ios::end);
60 int64_t len = in.tellg();
61 setContentLength(len);
62 std::string header=getHeader();
63 s.server_write(confd,(char*)header.c_str(),header.size());
64 in.seekg(0,std::ios::beg);
65 ssize_t n=0;
66 char buf[1024];
67 while(!in.eof()){
68 bzero(buf,sizeof(buf));
69 in.getline(buf,1024);
70 buf[strlen(buf)]='\n';
71 n+=s.server_write(confd,buf,in.gcount());
72 }
73 s.server_close(confd);
74 return n;
75 }
76 ssize_t HttpResponse::sendIndexFile(int confd,std::string file){
77 std::ifstream in(file.c_str());
78 in.seekg(0,std::ios::end);
79 int64_t len = in.tellg();
80 setContentLength(len);
81 std::string header=getHeader();
82 s.server_write(confd,(char*)header.c_str(),header.size());
83 in.seekg(0,std::ios::beg);
84 char buf[1024];
85 int sendCount=0;
86 while(!in.eof()){
87 memset(buf,0,sizeof(buf));
88 in.getline(buf,1024);
89 sendCount+=s.server_write(confd,buf,in.gcount());
90 }
91 s.server_close(confd);
92 return sendCount;
93 }
94 ssize_t HttpResponse::sendFile(int &confd,std::string fileName,int64_t pos){
95 std::ifstream in(fileName.c_str(),std::ios::binary);
96 in.seekg(0, std::ios::end);
97 std::streampos ps = in.tellg();
98 int64_t len=ps-pos;
99 if(pos!=0){
100 setStatusCode("206 Partial Content");
101 }
102 setContentType("application/octet-stream");
103 setContentLength(len);
104 std::string content="bytes";
105 content+=" "+Utils::toString(pos)+"-"+Utils::toString((int64_t)ps-1)+"/"+Utils::toString(len);
106 setContentRange(content);
107 std::string header=getHeader();
108 std::cout<
109 s.server_write(confd,(char*)header.c_str(),header.size());
110 in.seekg(pos,std::ios::beg);
111 char buf[1024];
112 ssize_t n=0;
113 while(!in.eof()){
114 in.read(buf,1024);
115 n+=s.server_write(confd,buf,in.gcount());
116 }
117 s.server_close(confd);
118 return n;
119 }
120 }

 

在上面響應(yīng)頭中Content-Range:這個(gè)字段,表示文件內(nèi)容的范圍,在一般情況下都是從0到lenth(file)-1。如果在之前已經(jīng)下了一些內(nèi)容后,如果是斷點(diǎn)續(xù)下載時(shí),瀏覽器在請求頭中有Range知道,表示從Range的開始字節(jié)傳輸,而我們服務(wù)器指定Content-Range為Range字段開始,接著發(fā)送這些內(nèi)容即可,實(shí)現(xiàn)文件的斷點(diǎn)下載。

責(zé)任編輯:何妍 來源: 博客園
相關(guān)推薦

2015-10-08 09:38:24

HTTP網(wǎng)絡(luò)協(xié)議文件傳輸

2015-09-29 09:25:20

HTTP網(wǎng)絡(luò)協(xié)議

2015-10-10 16:46:14

HTTP網(wǎng)絡(luò)協(xié)議文件傳輸

2015-09-28 13:39:13

Http網(wǎng)絡(luò)協(xié)議HTTP

2020-12-02 11:48:05

TFTP

2019-04-23 10:48:55

HTTPTomcat服務(wù)器

2011-08-18 16:03:34

iPhone上傳圖片

2018-10-09 09:28:12

HTTPHTTP協(xié)作服務(wù)器

2022-03-01 20:33:50

服務(wù)web項(xiàng)目

2020-06-17 21:39:11

HTTP協(xié)議服務(wù)器

2010-05-25 13:20:46

http與svn

2017-11-10 08:58:49

Web服務(wù)器應(yīng)用程序

2009-07-03 13:05:47

JSP HTTP服務(wù)器

2018-06-15 10:25:43

Python HTTPFTP服務(wù)器

2018-12-06 09:23:33

2019-04-24 15:06:37

Http服務(wù)器協(xié)議

2009-07-06 17:25:22

JSP HTTP服務(wù)器

2010-03-22 12:57:46

Java Socket

2012-03-27 11:08:23

Java

2009-07-06 17:56:12

JSP HTTP服務(wù)器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號