一、引言

欢迎大家和我一起编写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+="--\r\n";
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服务器实现文件上传与下载(六)》中进行讲解。

Http服务器实现文件上传与下载(五)的更多相关文章

  1. Http服务器实现文件上传与下载(四)

    一.引言 欢迎大家来到和我一起编写Http服务器实现文件的上传和下载,现在我稍微回顾一下之前我说的,第一.二章说明说明了整体的HTTP走向,第三章实现底层的网络编程.接着这一章我想给大家讲的是请求获取 ...

  2. java使用Jsch实现远程操作linux服务器进行文件上传、下载,删除和显示目录信息

    1.java使用Jsch实现远程操作linux服务器进行文件上传.下载,删除和显示目录信息. 参考链接:https://www.cnblogs.com/longyg/archive/2012/06/2 ...

  3. Http服务器实现文件上传与下载(一)

    一.引言 大家都知道web编程的协议就是http协议,称为超文本传输协议.在J2EE中我们可以很快的实现一个Web工程,但在C++中就不是非常的迅速,原因无非就是底层的socket网络编写需要自己完成 ...

  4. Http服务器实现文件上传与下载(二)

    一.引言 欢迎大家接着看我的博客,如何大家有什么想法的话回复我哦,闲话不多聊了,接着上一讲的内容来说吧,在上一节中已经讲到了请求头字符串的解析,并且在解析中我我们已经获取了url.就是上节中提到的/d ...

  5. Http服务器实现文件上传与下载(三)

    一.引言 在前2章的内容基本上已经讲解了整个的大致流程.在设计Http服务器时,我设计为四层的结构,最底层是网络传输层,就是socket编程.接着一层是请求和响应层,叫做Request和Respons ...

  6. java代码实现ftp服务器的文件上传和下载

    java代码实现文件上传到ftp服务器: 1:ftp服务器安装: 2:ftp服务器的配置: 启动成功: 2:客户端:代码实现文件的上传与下载: 1:依赖jar包: 2:sftpTools   工具类: ...

  7. 【问题解决方案】Xshell连接服务器并实现上传和下载文件

    参考链接: Xshell连接服务器并实现上传和下载文件 第一步:xshell登录完成 略 第二步: 在服务器安装lrzsz 如果服务器的操作系统是 CentOS,则输入命令[yum install l ...

  8. java web学习总结(二十四) -------------------Servlet文件上传和下载的实现

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  9. (转载)JavaWeb学习总结(五十)——文件上传和下载

    源地址:http://www.cnblogs.com/xdp-gacl/p/4200090.html 在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传 ...

随机推荐

  1. php抽象类和接口的异同【转】

    1. 相同点: (1)      两者都是抽象类,都不能实例化. (2)      interface 实现类及 abstract class 的子类都必须要实现已经声明的抽象方法. 2. 不同点: ...

  2. centos7(vmware install) 安装EMQ注意事项 ---控制台远程访问

    若想远端访问控制台,需打开对于端口 TCP 服务端口占用 EMQ 2.0 消息服务器默认占用的 TCP 端口包括: 1883 MQTT 协议端口 8883 MQTT/SSL 端口 8083 MQTT/ ...

  3. NOJ 1012 进制转换(十进制转换成随意进制)

    题目: 进制转换 时间限制(普通/Java) : 1000 MS/ 3000 MS          执行内存限制 : 65536 KByte总提交 : 1819            測试通过 : ...

  4. php的instanceof和判断闭包Closure

    类型运算符 instanceof 用于确定一个 PHP 变量是否属于某一类 class 的实例,在此之前用 is_a(),但是后来 is_a() 被废弃 <?php class MyClass ...

  5. 安装yii2高级应用模板

    composer global require "fxp/composer-asset-plugin:1.0.0" composer create-project --prefer ...

  6. 1.GCC编译过程

    一. GCC编译过程 gcc -E hello.c -o hello.i // 预处理.将代码中包含的头文件和宏进行替换 gcc -S hello.i -o hello.s // 汇编.将当前文本转换 ...

  7. haproxy配置tcp负载均衡

    #---------------------------------------------------------------------# 监控页面 #---------------------- ...

  8. jsp中跳出循环

    <c:otherwise> <c:set var="flag" value="true" /><!-- 设置flag --> ...

  9. PHP学习笔记(12)分页技术

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. linux学习笔记32---命令ping和telnet

    Linux系统的ping命令是常用的网络命令,它通常用来测试与目标主机的连通性,我们经常会说“ping一下某机器,看是不是开着”.不能打开网页时会说“你先ping网关地址192.168.1.1试试”. ...