HTTP服务器实现文件上传与下载

HTTP服务器实现文件上传与下载
HTTP服务器实现文件上传与下载

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

一、引言

大家都知道web编程的协议就是http协议,称为超文本传输协议。在J2EE中我们可以很快的实现一个Web工程,但在C++中就不是非常的迅速,原因无非就是底层的socket网络编写需要自己完成,上层的http协议需要我们自己完成,用户接口需要我们自己完成,如何高效和设计一个框架都是非常困难的一件事情。但这些事情Java已经在底层为我们封装好了,而我们仅仅只是在做业务层上的事情吧了。

在本Http服务器实现中,利用C++库和socket原套接字编程和pthread线程编写。拒绝使用第三方库。因为主要是让大家知道基本的实现方式,除去一些安全、高效等特性,但是不管怎么样,第三方商业库的基本原理还是一致的,只是他们对其进行了优化而已。在开始的编写时,我不会全部的简介Http的协议的内容,这样太枯燥了,我仅仅解释一些下面需要用到的协议字段。

在写本文的时候,之前也有些迷惑,C++到底能干啥,到网上一搜,无非就是能开发游戏,嵌入式编程,写服务器等等。接着如果问如何编写一个服务器的话,那么这些网络水人又会告诉你,你先把基础学好,看看什么书,之后你就知道了,我只能呵呵了,在无目的的学习中,尽管看了你也不知道如何写的,因为尽管你知道一些大概,但是没有一个人领导你入门,我们还是无法编写一个我们自己想要的东西,我写这篇博客主要是做一个小小的敲门砖吧,尽管网上有许多博客,关于如何编写HTTP服务器的,但是要不是第三方库acl,要么就是短短的几行代码,要么就是加入了微软的一些C#内容或者MFC,这些在我看来只是一些无关紧要的东西,加入后或许界面上你很舒服,但是大大增加了我们的学习成本,因为这些界面上的代码改变了我们所知道的程序流程走向,还有一些界面代码和核心代码的混合,非常不利于学习。

二、HTTP协议

在大家在浏览器的url输入栏上输入http://10.1.18.4/doing时。浏览器向10.1.18.4服务器80端口的进程发送了如下的一个协议头,它是一个文本字符串。每行以\r\n结束。表示回车换行。

1GET/doing HTTP/1.1

2Host:10.1.18.4

3User-Agent:Mozilla/5.0(Windows NT6.2;rv:40.0)Gecko/20100101 Firefox/40.0

4Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

5Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3

6Accept-Encoding:gzip,deflate

7Referer:http://10.1.18.4/

8Connection:keep-alive

所以知道其实我们发送了一个URL请求,其实被转化为了一个如上的一些字符串。在这里我简单的解释一下这个协议头表示什么,因为在网上你可以找到非常多的信息来解释它们。

1)第一行中GET/doing HTTP1.1表示请求的方式是GET,URL是/doing,HTTP协议的版本是1.1

2)第二行中Host就是服务器的IP

3)第三行中User-Agent代表着你使用的是什么浏览器在什么系统上运行的。从上本可以这条信息显示是window上火狐浏览器发出的请求头

4)第四行中Accept代表着该浏览器可以接受的信息格式,可以是文本,html,或者应用文件(二进制文件)。其中q代表权重,表示更愿意接受前面的信息。还有一些其他的内容,读者

可以自己百度。

5)以下的一些信息中,没有什么用到,我就不解释,看文本意义也大概知道一些信息。详细的请搜索网络。

在最重要的是一本请求头什么时候表示结束呢,那就是一个空行表示结束。其实就是"\r\n"结束。

说了这么多可能大家还是有点迷糊,知道这些那么在程序中又是怎么实现的呢。当初我也迷惑,现在我提出一个最简单的一种实现,就是直接连接一个字符串即可。在实际实现中我对其进行了分解,但是现在,我解释为如下编写程序:

1char*str="GET/doing HTTP/1.1\r\n\

2Host:10.1.18.4\r\n\

3User-Agent:Mozilla/5.0(Windows NT6.2;rv:40.0)Gecko/20100101 Firefox/40.0\r\n\

4Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*//*;q=0.8\ r\n\

5Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3\r\n\

6Accept-Encoding:gzip,deflate\r\n\

7Referer:http://10.1.18.4/\r\n\

8Connection:keep-alive\r\n\

9Range:bytes=14584264-\r\n\r\n";

可能上面的协议内容跟之前的有点不一样,没关系,我只是截取了一些内容进行输入。很简单就是C语言的char*字符串。在没一行的的结尾都都有一个'\',表示表示换行输入,去掉也行,需要把器内容写到一行上,是C语言语法,不懂的读者可以自己查阅C语言的字符串。我想说的是在每行的结尾都有一个\r\n。这两个转义字符就是代表回车换行。并且在第9行有2个\r\n,最后一个代表着空行,意思是说告诉服务器我的协议头到此位置。

为什么需要一个空行呢,这里就有一个网络编程的小小信息。在socket TCP流编程中,比如你调用了write或read函数,内部不是一次性接受或者发送所有的信息。所以当我们发送上述的str的时候,不一定一次全部的发送,那么服务端就不知道什么时候结尾了。所以我们需要HTTP规定以空行作为结尾代表着协议头的结束。

接下面了来就是我们编写的服务器接受到这个字符串。并且以空行表示接受到整个协议头,然后对其进行解析。下面就是解析这段字符串的代码,在工程中我对其封装,但是现在我们只要知道实现解析功能即可。

1#include

2#include

3#include

4#include

5#include

6using namespace std;

7

8char*str="GET/download/JBPM4S.tt HTTP/1.1\r\n\

9Host:10.1.18.4\r\n\

10User-Agent:Mozilla/5.0(Windows NT6.2;rv:40.0)Gecko/20100101 Firefox/40.0\r\n\

11Accept:

text/html,application/xhtml+xml,application/xml;q=0.9,*//*;q=0.8\ r\n\

12Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3\r\n\

13Accept-Encoding:gzip,deflate\r\n\

14Referer:http:http://10.1.18.4/\r\n\

15Connection:keep-alive\r\n\

16Range:bytes=14584264-\r\n\r\n";

17

18string<rim(string&str){

19string::iterator p=find_if(str.begin(),str.end(),not1(ptr_fun 20str.erase(str.begin(),p);

21return str;

22}

23

24string&rtrim(string&str){

25string::reverse_iterator p=find_if(str.rbegin(),str.rend(), not1(ptr_fun(isspace)));

26str.erase(p.base(),str.end());

27return str;

28}

29

30string&trim(string&str){

31ltrim(rtrim(str));

32return str;

33}

34string getContent(string&str,int start,char c,int&pos){

35int i=start;

36int len=str.size();

37while(i

38i++;

39}

40pos=i;

41return str.substr(start,i-start);

42}

43map

44int len=strlen(str);

45vector vs;

46int i=0;

47while(i

48if(str[i]!='\r'){

49int j=i;

50while(i

51i++;

52vs.push_back(string(str+j,str+i));

53}else{

54i+=2;

55}

56}

57int pos;

58string method=getContent(vs[0],0,'',pos);

59string url=getContent(vs[0],method.size()+1,'',pos);

60map

61mp["Method"]=method;

62mp["Url"]=url;

63for(int i=1;i

64string key=getContent(vs[i],0,':',pos);

65string value=vs[i].substr(pos+1);

66mp[key]=trim(value);

67}

68return mp;

69}

70

71int main(int argc,char**argv)

72{

73map

74for(map

75cout<

76}

77return0;

78}

把一些信息解析都放到了一个map里面。这里的解析是先处理每一行,然后再对每一行进行解析。可能这样的处理方式有点慢,但是没什么关系,原因是字符串反正比较短,在大并发下效率不会影响太大,如果大家有什么更好的解析方式,可以回复我。

在服务端解析头信息后,我们可以得到/doing这个url,这样我们服务请就可以把客户端需要的内容返回给客户端了,这里就有浏览器请求的内容是否合法是否存在这些信息。就要在相应的响应头中说明,在《Http服务器实现文件上传与下载(二)》中会进行说明。

欢迎大家一起探讨这些问题。有什么想法的人给我回复,我们一起学习,一起进步哦。【编辑推荐】

HTTP网络协议中的HTTP Client Hints技术

一些安全相关的HTTP响应头

漫谈:HTTP网络协议中Vary响应头

漫谈:Http网络协议中的Proxy-Connection

漫谈:Http网络协议中的X-Forwarded-For

ABAP-本地文件上载到SAP 服务器

DATA: fname TYPE rlgrap-filename, ftype TYPE rlgrap-filetype, fsize TYPE i. DATA: fname_p TYPE string, fname_n TYPE string. DATA: sfname_p TYPE string . DATA: sfname LIKE rcgiedial-iefile. sfname_p = './'. DATA: r(1) TYPE c. DATA: data_tab LIKE rcgrepfile OCCURS 10 WITH HEADER LINE. DATA: lines TYPE i. CALL FUNCTION 'UPLOAD' EXPORTING filename = 'c:/' filetype = 'BIN' filetype_no_change = 'X' IMPORTING filesize = fsize act_filename = fname act_filetype = ftype TABLES data_tab = data_tab EXCEPTIONS conversion_error = 1 invalid_table_width = 2 invalid_type = 3. fname_n = fname. DO. SPLIT fname_n AT '/' INTO fname_p fname_n. SEARCH fname_n FOR '/'. IF sy-subrc = 4. EXIT.

ENDIF. ENDDO. fname_p = fname. SHIFT fname_p RIGHT DELETING TRAILING fname_n. SHIFT fname_p LEFT DELETING LEADING space. CONCATENATE sfname_p fname_n INTO sfname. DESCRIBE TABLE data_tab LINES lines. CALL FUNCTION 'C13Z_RAWDATA_WRITE' EXPORTING i_file = sfname i_file_size = fsize i_lines = lines TABLES i_rcgrepfile_tab = data_tab EXCEPTIONS no_permission = 1 open_failed = 2 OTHERS = 3. IF sy-subrc NE 0. MESSAGE i000(znyj13) WITH 'UPLOAD SUCC'. ENDIF. WRITE: 'SY-SUBRC:', sy-subrc, / '上载的本地文件名:', (60) fname, / '上载的远程文件名:',(60) sfname, / '文件类型:', ftype, / '文件大小:', fsize. SKIP.

在WinForm中通过HTTP协议向服务器端上传文件

在WinForm中通过HTTP协议向服务器端上传文件相信用https://www.360docs.net/doc/6e14482940.html,写一个上传文件的网页大家都会写但是有没有人想过通过在WinForm中通过HTTP协议上传文件呢有些人说要向服务器端上传文件用FTP协议不是很简单吗效率又高为什么还要使用HTTP协议那么麻烦呢这里面有几个原因1FTP服务器的部署相对麻烦还要设置权限权限设置不对还会惹来一系列的安全问题。2如果双方都还有防火墙又不想开发FTP相关的一些端口时HTTP就会大派用场就像WEB Services能穿透防火墙一样。3其他的...还在想呢... 但是使用HTTP也有他的一些问题例如不能断点续传大文件上传很难速度很慢所以HTTP协议上传的文件大小不应该太大。说了这么多原归正传一般来说在Winform里通过HTTP 上传文件有几种可选的方法1前面提到的Web Services就是一种很好的方法通过编写一个WebMethod包含有byte 类型的参数然后调用Web Services的方法文件内容就会以Base64编码传到服务器上然后重新保存即可。WebMethod public void UploadFilebyte contentstring filename... Stream sw new StreamWriter... sw.Close 当然这种通过Base64编码的方法效率比较低那么可以采用WSE支持附件并以2进制形式传送效率会更高。2除了通过WebService另外一种更简单的方法就是通过WebClient或者HttpWebRequest来模拟HTTP的POST动作来实现。这时候首先需要编写一个https://www.360docs.net/doc/6e14482940.html,

用ACCESS向ftp服务器上传文件

用ACCESS向ftp服务器上传文件 用API调用: '声明: Private Declare Function InternetOpen Lib "wininet.dll" Alias "InternetOpenA" _ (ByVal sAgent As String, ByVal lAccessType As Long, ByVal sProxyName As String, _ ByVal sProxyBypass As String, ByVal lFlags As Long) As Long Private Declare Function InternetConnect Lib "wininet.dll" Alias "InternetConnectA" _ (ByVal hInternetSession As Long, ByVal sServerName As String, _ ByVal nServerPort As Integer, ByVal sUsername As String, _ ByVal sPassword As String, ByVal lService As Long, _ ByVal lFlags As Long, ByVal lContext As Long) As Long Private Declare Function FtpGetFile Lib "wininet.dll" Alias "FtpGetFileA" _ (ByVal hFtpSession As Long, ByVal lpszRemoteFile As String, _ ByVal lpszNewFile As String, ByVal fFailIfExists As Boolean, _ ByVal dwFlagsAndAttributes As Long, ByVal dwFlags As Long, _ ByVal dwContext As Long) As Boolean Private Declare Function FtpPutFile Lib "wininet.dll" Alias "FtpPutFileA" _ (ByVal hFtpSession As Long, ByVal lpszLocalFile As String, _ ByVal lpszRemoteFile As String, ByVal dwFlags As Long, _ ByVal dwContext As Long) As Boolean Private Declare Function InternetCloseHandle Lib "wininet.dll" (ByVal hInet As Long) As Integer '函数 Private Function UpLoadFile(ByVal LocateFile As String, ByVal RemoteFile As String) As

goAhead上实现文件上传到嵌入式Web服务器上

goAhead上实现文件上传到嵌入式Web服务器上 本文内容概要:详细描述了在goAhead 2.5上如何实现文件上传(上传文件)到服务器端的功能。 开发环境: 宿主机:Windows XP; 虚拟机:Ubuntu 9.10; 交叉编译器:arm-uclibc-gcc(arm-linux-gcc-4.3.2可以顺利编译通过)——————————————————————————————————— 1. 说明 最近调试web文件上传到服务器功能,但在调试时,处理函数总是获取不到文件路径,百思不得其解,查了网上许多文章,但大多提到的是前端文件上传的原理、实现方式等,而未提供服务器端处理的实现(利用C函数实现)。此外,由于对web不了解,花了些时间研究web程序。 2. goAhead实现文件上传的方法 总得来说,goAhead上实现文件上传功能是比较容易的。因为有现成的代码可用,稍微移植下即可。 2.1 实现原理 使用html form即表单提交文件上传请求,web服务器核心处理接收客户端Post过来的文件数据(注意post的是二进制数据),最后,web服务器把接收到文件数据以二进制格式写到服务器本端存储系统。 2.2 前端设计 前端设计比较简单,就是设计一个form,type属性为file,本人是在goAhead-2.5附带的wwwdemo的asptest.asp网页上增加了一个这样的form。 1. 2. 3. 4. 5.