libuv httpparser写的简单http server
libuv文档地址:http://docs.libuv.org/en/v1.x/
代码地址:https://github.com/libuv/libuv
http-parser https://github.com/nodejs/http-parser
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "uv.h"
#include "http_parser.h"
struct header
{
char field[1024];
char value[1024];
};
typedef enum { NONE=0, FIELD, VALUE } head_type;
struct message
{
int header_num;
char url[1024];
header headers[15];
head_type last_header_element;
};
int on_message_begin(http_parser* parser);
int on_headers_complete(http_parser* parser);
int on_message_complete(http_parser* parser);
int on_url(http_parser* parser, const char* at, size_t length);
int on_status(http_parser* parser, const char* at, size_t length);
int on_header_field(http_parser* parser, const char* at, size_t length);
int on_header_value(http_parser* parser, const char* at, size_t length);
int on_body(http_parser* parser, const char* at, size_t length);
int on_chunk_header(http_parser* parser);
int on_chunk_complete(http_parser* parser);
/* strnlen() is a POSIX.2008 addition. Can't rely on it being available so
* define it ourselves.
*/
size_t
strnlen(const char *s, size_t maxlen)
{
const char *p;
p = (const char *)memchr(s, '\0', maxlen);
if (p == NULL)
return maxlen;
return p - s;
}
size_t
strlncat(char *dst, size_t len, const char *src, size_t n)
{
size_t slen;
size_t dlen;
size_t rlen;
size_t ncpy;
slen = strnlen(src, n);
dlen = strnlen(dst, len);
if (dlen < len) {
rlen = len - dlen;
ncpy = slen < rlen ? slen : (rlen - 1);
memcpy(dst + dlen, src, ncpy);
dst[dlen + ncpy] = '\0';
}
assert(len > slen + dlen);
return slen + dlen;
}
size_t
strlcat(char *dst, const char *src, size_t len)
{
return strlncat(dst, len, src, (size_t) -1);
}
size_t
strlncpy(char *dst, size_t len, const char *src, size_t n)
{
size_t slen;
size_t ncpy;
slen = strnlen(src, n);
if (len > 0) {
ncpy = slen < len ? slen : (len - 1);
memcpy(dst, src, ncpy);
dst[ncpy] = '\0';
}
assert(len > slen);
return slen;
}
size_t
strlcpy(char *dst, const char *src, size_t len)
{
return strlncpy(dst, len, src, (size_t) -1);
}
#define CHECK(r, msg) \
if (r) { \
fprintf(stderr, "%s: %s\n", msg, uv_strerror(r)); \
exit(1); \
}
#if 0
#define UVERR(err, msg) fprintf(stderr, "%s: %s\n", msg, uv_strerror(err))
#define LOG(msg) puts(msg);
#define LOGF(fmt, ...) printf(fmt, ##__VA_ARGS__);
#define LOG_ERROR(msg) puts(msg);
#else
#define UVERR(err, msg)
#define LOG(msg)
#define LOGF(fmt, ...)
#define LOG_ERROR(msg)
#endif
#define RESPONSE \
"HTTP/1.1 200 OK\r\n" \
"Content-Type: text/plain\r\n" \
"Content-Length: 12\r\n" \
"\r\n" \
"hello world\n"
static uv_loop_t* uv_loop;
static uv_tcp_t server;
static http_parser_settings parser_settings;
static uv_buf_t resbuf;
static uv_async_t async;//异步任务
typedef struct {
uv_tcp_t handle;
http_parser parser;
uv_write_t write_req;
int request_num;
message msg;
} client_t;
void on_close(uv_handle_t* handle) {
client_t* client = (client_t*) handle->data;
LOGF("[ %5d ] connection closed\n", client->request_num);
free(client);
printf("on_close\n");
}
void on_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
//suggested_size = 10;
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
LOGF("on_alloc %p\n", buf->base);
}
void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
size_t parsed;
client_t* client = (client_t*) tcp->data;
if (nread >= 0) {
parsed = http_parser_execute(
&client->parser, &parser_settings, buf->base, nread);
if (parsed < nread) {
struct sockaddr_in addr;
char ipv4addr[64];
int namelen = sizeof(addr);
uv_tcp_getpeername((const uv_tcp_t*)tcp, (struct sockaddr*)&addr, &namelen);
uv_ip4_name(&addr, ipv4addr, 64);
LOGF("parse error,peer addr %s\n", ipv4addr);
printf("parse error,peer addr %s\n", ipv4addr);
uv_close((uv_handle_t*) &client->handle, on_close);
}
} else {
if (nread != UV_EOF)
UVERR(nread, uv_err_name(nread));
printf("on_read nread==0\n");
uv_close((uv_handle_t*) client, on_close);
}
LOGF("free alloc %p\n", buf->base);
free(buf->base);
uv_async_send(&async);
}
static int request_num = 0;
static int request_pre = request_num;
void on_connect(uv_stream_t* server_handle, int status) {
CHECK(status, "connect");
int r;
assert((uv_tcp_t*)server_handle == &server);
client_t* client = (client_t*)malloc(sizeof(client_t));
client->request_num = request_num;
client->msg.last_header_element = NONE;
client->msg.header_num = 0;
memset(&client->msg, 0, sizeof(client->msg));
++request_num;
//LOGF("[ %5d ] new connection\n", request_num++);
uv_tcp_init(uv_loop, &client->handle);
http_parser_init(&client->parser, HTTP_REQUEST);
client->parser.data = client;
client->handle.data = client;
r = uv_accept(server_handle, (uv_stream_t*)&client->handle);
CHECK(r, "accept");
uv_read_start((uv_stream_t*)&client->handle, on_alloc, on_read);
}
void fake_job(uv_timer_t *handle)
{
fprintf(stdout, "rate %d\n", request_num-request_pre);
request_pre = request_num;
}
void after_write(uv_write_t* req, int status) {
CHECK(status, "write");
uv_close((uv_handle_t*)req->handle, on_close);
}
//异步处理过程
void on_async_cb(uv_async_t* handle)
{
printf("on_async_cb\n");
}
int main() {
int r;
struct sockaddr_in addr;
char listen_ip[] = "0.0.0.0";
int port = 7070;
parser_settings.on_message_begin = on_message_begin;
parser_settings.on_url = on_url;
parser_settings.on_status = on_status;
parser_settings.on_header_field = on_header_field;
parser_settings.on_header_value = on_header_value;
parser_settings.on_headers_complete = on_headers_complete;
parser_settings.on_body = on_body;
parser_settings.on_message_complete = on_message_complete;
parser_settings.on_chunk_header = on_chunk_header;
parser_settings.on_chunk_complete = on_chunk_complete;
resbuf.base = RESPONSE;
resbuf.len = strlen(RESPONSE);
uv_loop = uv_default_loop();
r = uv_tcp_init(uv_loop, &server);
CHECK(r, "bind");
uv_ip4_addr(listen_ip, port, &addr);
r = uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);
CHECK(r, "bind");
uv_listen((uv_stream_t*)&server, 128, on_connect);
printf("listening on %s:%d\n", listen_ip,port);
//uv_timer_t fake_job_req;
//uv_timer_init(uv_loop, &fake_job_req);
//uv_timer_start(&fake_job_req, fake_job, 1000, 1000);
uv_async_init(uv_loop, &async, on_async_cb);
uv_run(uv_loop, UV_RUN_DEFAULT);
}
int on_message_begin(http_parser* parser) {
//printf("\n***MESSAGE BEGIN***\n\n");
return 0;
}
int on_headers_complete(http_parser* parser) {
client_t* client = (client_t*) parser->data;
LOGF("[ %5d ] http message parsed\n", client->request_num);
return 0;
}
int on_message_complete(http_parser* parser) {
//printf("\n***MESSAGE COMPLETE***\n\n");
client_t* client = (client_t*) parser->data;
uv_write(
&client->write_req,
(uv_stream_t*)&client->handle,
&resbuf,
1,
after_write);
return 0;
}
int on_url(http_parser* parser, const char* at, size_t length) {
client_t * client = (client_t*)parser->data;
strlncat(client->msg.url,
1024, at, length);
//printf("Url: %d,%s\n", (int)length, client->msg.url);
return 0;
}
int on_status(http_parser* parser, const char* at, size_t length) {
client_t * client = (client_t*)parser->data;
strlncat(client->msg.url,
1024, at, length);
//printf("status: %d,%s\n", (int)length, client->msg.url);
return 0;
}
int on_header_field(http_parser* parser, const char* at, size_t length) {
//printf("Header field: %d,%p\n", (int)length, at);
client_t * client = (client_t*)parser->data;
if (client->msg.last_header_element != FIELD)
{
++client->msg.header_num;
}
strlncat(client->msg.headers[client->msg.header_num-1].field,
1024, at, length);
client->msg.last_header_element = FIELD;
return 0;
}
int on_header_value(http_parser* parser, const char* at, size_t length) {
//printf("Header value: %d,%p\n", (int)length, at);
client_t * client = (client_t*)parser->data;
strlncat(client->msg.headers[client->msg.header_num-1].value,
1024, at, length);
client->msg.last_header_element = VALUE;
return 0;
}
int on_body(http_parser* parser, const char* at, size_t length) {
//printf("Body: %d,%p\n", (int)length, at);
return 0;
}
int on_chunk_header(http_parser* parser) {
//printf("\n***chunk_header***\n\n");
return 0;
}
int on_chunk_complete(http_parser* parser) {
//printf("\n***chunk_complete***\n\n");
return 0;
}
libuv httpparser写的简单http server的更多相关文章
- 用libevent写个简单的server/client
libevent是一个轻量级的事件触发库,可以很好地利用在网络通讯上面,用其进行大量的异步,延时,重发等场景. 下面是一个server的demo #include include void cb_fu ...
- 用Python写一个简单的Web框架
一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...
- 如何写一个简单的http服务器
最近几天用C++写了一个简单的HTTP服务器,作为学习网络编程和Linux环境编程的练手项目,这篇文章记录我在写一个HTTP服务器过程中遇到的问题和学习到的知识. 服务器的源代码放在Github. H ...
- (2)自己写一个简单的servle容器
自己写一个简单的servlet,能够跑一个简单的servlet,说明一下逻辑. 首先是写一个简单的servlet,这就关联到javax.servlet和javax.servlet.http这两个包的类 ...
- (原创)如何使用boost.asio写一个简单的通信程序(一)
boost.asio相信很多人听说过,作为一个跨平台的通信库,它的性能是很出色的,然而它却谈不上好用,里面有很多地方稍不注意就会出错,要正确的用好asio还是需要花一番精力去学习和实践的,本文将通过介 ...
- 如何写一个简单的HTTP服务器(重做版)
最近几天用C++重新写了之前的HTTP服务器,对以前的代码进行改进.新的HTTP服务器采用Reactor模式,有多个线程并且每个线程有一个EventLoop,主程序将任务分发到每个线程,其中采用的是轮 ...
- 如何写一个简单的webserver(一):最简实现
本文主要讲述如何用C/C++在Linux环境下写一个简单的支持并发的web服务器,并不考虑服务器的健壮性.安全性.性能等一系列因素. 在本文中,该服务器仅支持GET请求. 项目地址:https://g ...
- 用flask写一个简单的接口
用falsk写一个简单的接口,这个接口的数据本来是爬虫爬取的数据,但是今天只写一个flask接口,数据就用测试数据好了. import random import re import time imp ...
- 手写一个简单的starter组件
spring-boot中有很多第三方包,都封装成starter组件,在maven中引用后,启动springBoot项目时会自动装配到spring ioc容器中. 思考: 为什么我们springBoot ...
随机推荐
- 在javascript中,我怎么得到下拉条顶端与当前可视的顶端高度的距离,不是和网页顶端的距离
"滚动条顶端距离" + document.documentElement.scrollTop)
- HDU 5514 Frogs (数论容斥)
题意:有n只青蛙,m个石头(围成圆圈).第i只青蛙每次只能条ai个石头,问最后所有青蛙跳过的石头的下标总和是多少? 析:首先可以知道的是第 i 只青蛙可以跳到 k * gcd(ai, m),然后我就计 ...
- 慕课网5-2编程练习:flex布局制作卡片布局案例
慕课网5-2编程练习:flex布局制作卡片布局案例 小伙伴们,学习了卡片布局,接下来我们根据效果图,也写出一个卡片布局的页面吧! 效果图如下: 任务 1.主体内容的卡片一行只能显示两个. 2.卡片与卡 ...
- 一文了解H5照片上传过程
一.选择拍照或文件 HTML: 使用<input>标签, type设为"file"选择文件, accept设为"image/*"选择文件为图片类型和 ...
- Elasticsearch的功能、使用场景以及特点
1.Elasticsearch的功能,干什么的 2.Elasticsearch的适用场景,能在什么地方发挥作用 3.Elasticsearch的特点,跟其他类似的东西不同的地方在哪里 1.Elasti ...
- [Usaco2006 Open]The Climbing Wall 攀岩
Description One of the most popular attractions at the county fair is the climbing wall. Bessie want ...
- Poj 2947 widget factory (高斯消元解同模方程)
题目连接: http://poj.org/problem?id=2947 题目大意: 有n种类型的零件,m个工人,每个零件的加工时间是[3,9],每个工人在一个特定的时间段内可以生产k个零件(可以相同 ...
- linux自动连接校园网设置
不知道有没有人用linux的时候碰到过校园网连接后,跳不出登录界面,即使手动输入也没有作用.写一个可能可行的方法: - 首先打开控制面板 选择网络代理 将代理中的选项设置为 估计现在就能自动弹出登录页 ...
- 12c debug 转 12C 连接CDB和PDB
来源:David Dai -- Focus on Oracle 连接到CDB 12c debug 和普通实例一样的连接. 指定ORACLE_SID 以后可以使用OS认证,也可以使用密码进行连接. [o ...
- spring tool suite开发环境搭建
先把是构建工具maven: maven里面有一个conf文件夹,然后里面有个setting.xml配置文件,先要把项目要的setting.xml覆盖这个原来的配置文件. 这个maven配置文件有一个作 ...