首页IT科技有关自我实现的名言(实现自己的http server loop_in_codes C++博客)

有关自我实现的名言(实现自己的http server loop_in_codes C++博客)

时间2025-09-19 04:44:23分类IT科技浏览5491
导读:实现自己的http server...

实现自己的http server

Write your own http server

author : Kevin Lynx

Why write your own?

看这个问题的人证明你知道什么是http server                ,世界上有很多各种规模的http server                      ,为什么要自己实现一个?其实没什么

理由              。我自己问自己       ,感觉就是在自己娱乐自己            ,或者说只是练习下网络编程                       ,或者是因为某日我看到某个库宣称自己附带一个小

型的http server时          ,我不知道是什么东西        ,于是就想自己去实现一个                       。

Whats httpd ?

httpd就是http daemon                        ,这个是类unix系统上的名称              ,也就是http server        。httpd遵循HTTP协议    ,响应HTTP客户端的request                        ,

然后返回response           。

那么                  ,什么是HTTP协议?最简单的例子,就是你的浏览器与网页服务器之间使用的应用层协议                      。虽然官方文档说HTTP协议可以

建立在任何可靠传输的协议之上                    ,但是就我们所见到的                      ,HTTP还是建立在TCP之上的            。

httpd最简单的response是返回静态的HTML页面        。在这里我们的目标也只是一个响应静态网页的httpd而已(也许你愿意加入CGI

特性)                      。

More details about HTTP protocol

在这里有必要讲解HTTP协议的更多细节    ,因为我们的httpd就是要去解析这个协议                。

关于HTTP协议的详细文档                ,可以参看rfc2616    。但事实上对于实现一个简单的响应静态网页的httpd来说                      ,完全没必要读这么一

分冗长的文档                      。在这里我推荐<HTTP Made Really Easy>       ,以下内容基本取自于本文档                    。

- HTTP协议结构

HTTP协议无论是请求报文(request message)还是回应报文(response message)都分为四部分:

* 报文头 (initial line )

* 0个或多个header line

* 空行(作为header lines的结束)

* 可选body

HTTP协议是基于行的协议            ,每一行以\r\n作为分隔符。报文头通常表明报文的类型(例如请求类型)                       ,报文头只占一行;header line

附带一些特殊信息          ,每一个header line占一行        ,其格式为name:value                        ,即以分号作为分隔;空行也就是一个\r\n;可选body通常

包含数据              ,例如服务器返回的某个静态HTML文件的内容                  。举个例子    ,以下是一个很常见的请求报文                        ,你可以截获浏览器发送的数据

包而获得:

1 GET /index.html HTTP/1.1

2 Accept-Language: zh-cn

3 Accept-Encoding: gzip, deflate

4 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; MAXTHON 2.0)

5 Host: localhost

6 Connection: Keep-Alive

7

我为每一行都添加了行号                  ,第1行就是initial line,2-6行是header lines                    ,7行是一个header line的结束符                      ,没有显示出来                        。

以下是一个回应报文:

1 HTTP/1.1 200 OK

2 Server: klhttpd/0.1.0

3 Content-Type: text/html

4 Content-Length: 67

5

6 index.htmlindex.html

第6行就是可选的body    ,这里是index.html这个文件的内容    。

- HTTP request method

因为我们做的事服务器端                ,所以我们重点对请求报文做说明              。首先看initial line                      ,该行包含几个字段       ,每个字段用空格分开            ,例

如以上的GET /index.html HTTP/1.1就可以分为三部分:GET                、/index.html                      、HTTP/1.1                       。其中第一个字段GET就是所谓的request

method        。它表明请求类型                       ,HTTP有很多method          ,例如:GET       、POST            、HEAD等           。

就我们的目标而言        ,我们只需要实现对GET和HEAD做响应即可                      。

GET是最普遍的method                        ,表示请求一个资源            。什么是资源?诸如HTML网页                       、图片          、声音文件等都是资源        。顺便提一句              ,HTTP协议

中为每一个资源设置一个唯一的标识符    ,就是所谓的URI(更宽泛的URL)                      。

HEAD与GET一样                        ,不过它不请求资源内容                  ,而是请求资源信息,例如文件长度等信息                。

- More detail

继续说说initial line后面的内容:

对应于GET和HEAD两个method                    ,紧接着的字段就是资源名                      ,其实从这里可以看出    ,也就是文件名(相对于你服务器的资源目录)                ,例

如这里的/index.html;最后一个字段表明HTTP协议版本号    。目前我们只需要支持HTTP1.1和1.0                      ,没有多大的技术差别                      。

然后是header line                    。我们并不需要关注每一个header line。我只罗列有用的header line :

- Host : 对于HTTP1.1而言       ,请求报文中必须包含此header            ,如果没有包含                       ,服务器需要返回bad request错误信息                  。

- Date : 用于回应报文          ,用于客户端缓存数据用                        。

- Content-Type : 用于回应报文        ,表示回应资源的文件类型                        ,以MIME形式给出    。什么是MIME?它们都有自己的格式              ,例如:

text/html, image/jpg, image/gif等              。

- Content-Length : 用于回应报文    ,表示回应资源的文件长度                       。

body域很简单                        ,你只需要将一个文件全部读入内存                  ,然后附加到回应报文段后发送即可,即使是二进制数据        。

- 回应报文

之前提到的一个回应报文例子很典型                    ,我们以其为例讲解           。首先是initial line                      ,第一个字段表明HTTP协议版本    ,可以直接以请求

报文为准(即请求报文版本是多少这里就是多少);第二个字段是一个status code                ,也就是回应状态                      ,相当于请求结果       ,请求结果

被HTTP官方事先定义            ,例如200表示成功        、404表示资源不存在等;最后一个字段为status code的可读字符串                       ,你随便给吧                      。

回应报文中最好跟上Content-Type                        、Content-Length等header            。

具体实现

正式写代码之前我希望你能明白HTTP协议的这种请求/回应模式          ,即客户端发出一个请求        ,然后服务器端回应该请求        。然后继续

这个过程(HTTP1.1是长连接模式                        ,而HTTP1.0是短连接              ,当服务器端返回第一个请求时    ,连接就断开了)                      。

这里                        ,我们无论客户端                  ,例如浏览器,发出什么样的请求                    ,请求什么资源                      ,我们都回应相同的数据:

程序以最简单的阻塞模式运行    ,我们可以将重点放在协议的分析上                。运行程序                ,在浏览器里输入http://localhost:8080/index.html

                      ,然后就可以看到浏览器正常显示content中描述的HTML文件    。假设程序在8080端口监听                      。

现在你基本上明白了整个工作过程       ,我们可以把代码写得更全面一点            ,例如根据GET的URI来载入对应的文件然后回应给客户端                    。

其实这个很简单                       ,只需要从initial line里解析出(很一般的字符串解析)URI字段          ,然后载入对应的文件即可。例如以下函数:

voidhttp_response(SOCKETcon,constchar*

request)

{

/**//*getthemethod*/char*token=strtok(request,""

);

char*uri=strtok(0,""

);

charfile[64

];

sprintf(file,
".%s"

,uri);

{

/**//*loadthefilecontent*/FILE*fp=fopen(file,"rb"

);

if(fp==0

)

{

/**//*response404statuscode*/charresponse[]="HTTP/1.1404NOTFOUND\r\n\r\n"

;

send(con,response,strlen(response),
0

);

}
else

{

/**//*responsetheresource*//**//*first,loadthefile*/int

file_size;

char*

content;

charresponse[1024

];

fseek(fp,
0

,SEEK_END);

file_size
=

ftell(fp);

fseek(fp,
0

,SEEK_SET);

content
=(char*)malloc(file_size+1

);

fread(content,file_size,
1

,fp);

content[file_size]
=0

;

sprintf(response,
"HTTP/1.1200OK\r\nContent-Type:text/html\r\nContent-Length:%d\r\n\r\n%s"

,file_size,content);

send(con,response,strlen(response),
0

);

free(content);

}
}
}

其他

要将这个简易的httpd做完善        ,我们还需要注意很多细节                  。包括:对不支持的method返回501错误;对于HTTP1.1要求有Host这个

header;为了支持客户端cache                        ,需要添加Date header;支持HEAD请求等                        。

相关下载中我提供了一个完整的httpd library              ,纯C的代码    ,在其上加上一层资源载入即可实现一个简单的httpd    。在这里我将

对代码做简要的说明:

evbuffer.h/buffer.c : 取自libevent的buffer                        ,用于缓存数据;

klhttp-internal.h/klhttp-internal.c :主要用于处理/解析HTTP请求                  ,以及创建回应报文;

klhttp-netbase.h/klhttp-netbase.c :对socket api的一个简要封装,使用select模型;

klhttp.h/klhttp.c :库的最上层                    ,应用层主要与该层交互                      ,这一层主要集合internal和netbase              。

test_klhttp.c :一个测试例子                       。

相关下载:

klhttpd

文中相关代码

参考资料:

http://www.w3.org/Protocols/rfc2616/rfc2616.html

http://jmarshall.com/easy/http/

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
声明:本站所有文章    ,如无特殊说明或标注                ,均为本站原创发布        。任何个人或组织                      ,在未征得本站同意时       ,禁止复制              、盗用    、采集                        、发布本站内容到任何网站                  、书籍等各类媒体平台           。如若本站内容侵犯了原著者的合法权益            ,可联系我们进行处理                      。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
织梦cms的数据库文件在哪(织梦DedeCMS二次开发教程之创建数据表)