也谈如何写一个Webserver(-)
关于如何写一个Webserver,很多大咖都发表过类似的文章.趁着这个五一假期,我也来凑个份子.
我写Webserver的原因,还得从如何将http协议传送的消息解析说起.当时,我只是想了解一下http的消息解析过程,好能够提高基于http协议的消息处理效率,所以就在网上搜了一下,发现很多人都在用nodejs的http-parser,也许是智商上限封顶^_^!,我居然没太看懂大神的代码逻辑.后来也考察过h2o这个项目的parser,无奈还是没有能领悟大神的精神^_^!.
怎么办...,挣扎了半天,最终决定硬着头皮自己写一个http消息的parser吧.就酱,就有了后来我写Maestro Webserver的故事.
既然谈到了http message的解析,那今天这第一篇随笔就谈这个东西吧.http协议的内容说起来历史太久远了,我不是历史老师,网上很多讲解都很棒,我就不多说了.此外,RFC2616, RFC7231等文档也明确的讲解了协议的含义.不过还是应该吐槽一下RFC文档的晦涩难懂哈...
还是让我引用一段相对清晰的关于http message的RFC讲解吧
HTTP messages consist of requests from client to server and responses
from server to client. HTTP-message = Request | Response ; HTTP/1.1 messages Request (section 5) and Response (section 6) messages use the generic
message format of RFC 822 [9] for transferring entities (the payload
of the message). Both types of message consist of a start-line, zero
or more header fields (also known as "headers"), an empty line (i.e.,
a line with nothing preceding the CRLF) indicating the end of the
header fields, and possibly a message-body. generic-message = start-line
*(message-header CRLF)
CRLF
[ message-body ]
start-line = Request-Line | Status-Line
从这段文字中,我们可以知道不论是request还是response,http message分三段,即start-line,message headers和message body.
那么,在设计我的messge结构体时(对了,我是用C语言开发的),我会包含这三段内容.我并没有把parser写成独立的单一函数,而是将他们分解成了一组能重复被调用的更小的函数.而从封装的角度来说,我也没有遵守尽量封装数据结构体的原则.我的目的很简单,那就是,简单易懂,容易调用(这会不会被老师调打一顿:-).
还是看看定义的数据结构体吧.
typedef struct {
int method; /* GET/POST... */
char *path;
int ver_major;
int ver_minor;
int code; /* status code */
char *status; /* status text */
sllist_t *headers;
int len_startline;
int len_headers;
unsigned char *body;
unsigned char *body_zipped;
unsigned char *body_s; /* point to the range start of the body */
size_t len_body;
} httpmsg_t;
先不用看和body相关的部分,因为我会在后续如何写Webserver中介绍相关的内容(涉及到body的压缩,断点续传等等).
下面是相关的函数,
int msg_parse(sllist_t *headers,
unsigned char **startline,
unsigned char **body,
size_t *len_body,
const unsigned char *buf);
这个是对底层message进行解析的函数,再此之上,我用两个函数封装了它,分别用于解析http request和http response.
httpmsg_t *http_parse_req(const unsigned char *buf);
httpmsg_t *http_parse_rep(const unsigned char *buf);
我写这些底层函数的原则是,尽量利用上一步的结果,不做重复的计算,比如,同一字符串的长度不要多次通过strlen计算,希望这样应该能提高(微不足道^_^!)的性能吧.
在上面的httpmsg_t结构体中,我用了单链表来管理http headers,因为headers的数量不是很多,单链表轮询反而速度更快.
至于上述函数如何实现,感兴趣朋友可以请访问我的github项目,链接https://github.com/grassroot72/Maestro2.
欢迎和我探讨..
我会在第二篇内容里介绍socket和epoll在Webserver中的应用...
也谈如何写一个Webserver(-)的更多相关文章
- 也谈如何写一个Webserver(三)
在上一篇里,我介绍了如何应用socket和epoll来组织和管理从客户端(如,浏览器)传入的连接,通过设置非阻塞连接让Webserver有更好的性能. 下面,我介绍一下在我写的Webserver Ma ...
- 比最差的API(ETW)更差的API(LTTng)是如何炼成的, 谈如何写一个好的接口
最近这几天在帮柠檬看她的APM系统要如何收集.Net运行时的各种事件, 这些事件包括线程开始, JIT执行, GC触发等等. .Net在windows上(NetFramework, CoreCLR)通 ...
- 如何写一个简单的webserver(一):最简实现
本文主要讲述如何用C/C++在Linux环境下写一个简单的支持并发的web服务器,并不考虑服务器的健壮性.安全性.性能等一系列因素. 在本文中,该服务器仅支持GET请求. 项目地址:https://g ...
- 郑晔谈 Moco 框架的开发:写一个好的内部 DSL ,写一个表达性好的程序
作者:张龙 出处:http://www.infoq.com/cn/news/2013/07/zhengye-on-moco 郑晔谈Moco框架的开发:写一个好的内部DSL,写一个表达性好的程序 作者 ...
- 张小龙谈如何写E-mail软件
编者语:鼎鼎大名的Foxmail软件制作者,你一定不会陌生吧!本刊第三期特刊还刊登过此君的生活照一张,可谓威风八面.小编此次突发奇想,“死缠烂打”,费了九牛二虎之力,终于约他写了一篇有关写E-mail ...
- Android在如何建立一个WebServer
今天老板交待任务最终完成了,感觉收获颇多,所以写一个关于它的记录,首先,看一下.老板的需求 需求: 希望移动端的用户标识(IMEI)和HTML页面的用户标识(Cookie)连接起来,当中HTML页面可 ...
- 用c++写一个 “hello,world” 的 FastCGI程序
原文:http://chriswu.me/blog/writing-hello-world-in-fcgi-with-c-plus-plus/ 上面的连接地址给出的是作者的原文地址. 另外一个作者稍微 ...
- 动手写一个简单版的谷歌TPU-指令集
系列目录 谷歌TPU概述和简化 基本单元-矩阵乘法阵列 基本单元-归一化和池化(待发布) TPU中的指令集 SimpleTPU实例: (计划中) 拓展 TPU的边界(规划中) 重新审视深度神经网络中的 ...
- 来,我们手写一个简易版的mock.js吧(模拟fetch && Ajax请求)
预期的mock的使用方式 首先我们从使用的角度出发,思考编码过程 M1. 通过配置文件配置url和response M2. 自动检测环境为开发环境时启动Mock.js M3. mock代码能直接覆盖g ...
随机推荐
- Java基础语法:变量与常量
一.命名规范 所有变量.常量.方法.类 都使用英文单词 命名,要见名知意. 所有变量.方法 的命名都使用小驼峰法 :首字母小写的驼峰命名法.例如:sampleText 类 的命名都使用大驼峰法 :首字 ...
- 第49天学习打卡(CSS 层次选择器 结构伪类选择器 属性选择器 美化网页元素 盒子模型)
推荐书籍:码出高效: Java 开发手册 2.2 层次选择器 idea里代码规范是按:ctrl +alt+L快捷键 注释快捷键:ctrl+/ 1.后代选择器:在某个元素的后面 祖爷爷 爷爷 爸爸 你 ...
- python进阶(12)闭包
闭包 首先了解一下:如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内部的我们叫他内函数. 在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用 ...
- fastjson 反弹shell
目录 如下文章说得很不详细,只是用于记录我的步骤,初次利用的人,建议找别的博客文章学习. 准备一台公网服务器 cd test python -m SimpleHTTPServer 8888 javac ...
- c# float类型和double类型相乘出现精度丢失
c# float类型和double类型相乘出现精度丢失 double db = 4.0; double db2 = 1.3; float f = 1.3F; float f2 = 4.0F; Deci ...
- vue 仿zTree折叠树
需求: vue实现仿zTree折叠树,此文章仅作为记录文档. 实现: <template> <div class="line-tree"> <div ...
- myeclipse js报错
Myeclipse 版本10.1 加载的js报错,解决方法: window -> preferences -> myeclipse -> validation,在右边下拉框找到 Ja ...
- android分析之Parcel
将数据打包,跨进程传输(通过Binder).看看这货究竟是啥玩意: Parcel.java : public final class Parcel { private static final boo ...
- Salesforce LWC学习(三十二)实现上传 Excel解析其内容
本篇参考:salesforce lightning零基础学习(十七) 实现上传 Excel解析其内容 上一篇我们写了aura方式上传excel解析其内容.lwc作为salesforce的新宠儿,逐渐的 ...
- 【linux】驱动-2-内核模块
目录 前言 2. 内核模块 2.1 内核模块概念 2.1.1 内核 2.1.2 内核模块机制的引入 2.2 内核模块 2.2.1 内核模块参考例程 2.2.2 内核模块命令 2.2.3 系统自动加载模 ...