最近在工作中使用到了libenevt封装的http,在做curl模拟get/post请求时遇到了一些问题,今天就记录下正确的http服务端处理方法,欢迎观摩。
一、libevent介绍
首先,咱们简单介绍下libevent。
libevent就是一个基于事件通知机制的库,支持/dev/poll、kqueue、event ports、select、poll和epoll事件机制,也因此它是一个跨操作系统的库(支持Linux、*BSD、Mac OS X、Solaris、Windows等)。目前应用该库的有Chromium、Memcached、NTP、tmux等应用。
libevent 库实际上没有更换select()、poll()或其他机制的基础,而是使用对于每个平台最高效的高性能解决方案,在其实现外加上一个包装器。
为了实际处理每个请求,libevent 库提供一种事件机制,它作为底层网络后端的包装器。事件系统让为连接添加处理函数变得非常简便,同时降低了底层 I/O 复杂性。这是 libevent 系统的核心。
libevent 库的其他组件提供其他功能,包括缓冲的事件系统(用于缓冲发送到客户端/从客户端接收的数据)以及 HTTP、DNS 和 RPC 系统的核心实现。
另外,libevent库非常轻量级,这让我们学习它的源码难度低了不少。
二、libevent安装
官网:http://libevent.org/
选择最新版本下载,然后安装README文件中描述的方法编译、安装即可。
./configure 或 ./configure -prefix=/usr //prefix表示输出文件路径
make
make verify # 可选操作
make install
# ls -al /usr/lib | grep libevent //测试libevent是否安装成功
安装完成后,就可以编码http服务器了。
三、libevent http服务器实例
#include <stdio.h>
#include <stdlib.h>
#include <evhttp.h>
#include <event.h>
#include <string.h>
#include "event2/http.h"
#include "event2/event.h"
#include "event2/buffer.h"
#include "event2/bufferevent.h"
#include "event2/bufferevent_compat.h"
#include "event2/http_struct.h"
#include "event2/http_compat.h"
#include "event2/util.h"
#include "event2/listener.h"
#define BUF_MAX 1024*16
void get_post_message(char *buf, struct evhttp_request *req)
{
size_t post_size = 0;
post_size = evbuffer_get_length(req->input_buffer);
printf("====line:%d,post len:%d\n",__LINE__,post_size);
if (post_size <= 0)
{
printf("====line:%d,post msg is empty!\n",__LINE__);
return;
}
else
{
size_t copy_len = post_size > BUF_MAX ? BUF_MAX : post_size;
printf("====line:%d,post len:%d, copy_len:%d\n",__LINE__,post_size,copy_len);
memcpy(buf, evbuffer_pullup(req->input_buffer,-1), copy_len);
buf[post_size] = '\0';
printf("====line:%d,post msg:%s\n",__LINE__,buf);
}
}
char *find_http_header(struct evhttp_request *req,struct evkeyvalq *params,const char *query_char)
{
if(req == NULL || params == NULL || query_char == NULL)
{
printf("====line:%d,%s\n",__LINE__,"input params is null.");
return NULL;
}
struct evhttp_uri *decoded = NULL;
char *query = NULL;
char *query_result = NULL;
const char *path;
const char *uri = evhttp_request_get_uri(req);
if(uri == NULL)
{
printf("====line:%d,evhttp_request_get_uri return null\n",__LINE__);
return NULL;
}
else
{
printf("====line:%d,Got a GET request for <%s>\n",__LINE__,uri);
}
decoded = evhttp_uri_parse(uri);
if (!decoded)
{
printf("====line:%d,It's not a good URI. Sending BADREQUEST\n",__LINE__);
evhttp_send_error(req, HTTP_BADREQUEST, 0);
return;
}
path = evhttp_uri_get_path(decoded);
if (path == NULL)
{
path = "/";
}
else
{
printf("====line:%d,path is:%s\n",__LINE__,path);
}
query = (char*)evhttp_uri_get_query(decoded);
if(query == NULL)
{
printf("====line:%d,evhttp_uri_get_query return null\n",__LINE__);
return NULL;
}
evhttp_parse_query_str(query, params);
query_result = (char*)evhttp_find_header(params, query_char);
return query_result;
}
void http_handler_testget_msg(struct evhttp_request *req,void *arg)
{
if(req == NULL)
{
printf("====line:%d,%s\n",__LINE__,"input param req is null.");
return;
}
char *sign = NULL;
char *data = NULL;
struct evkeyvalq sign_params = {0};
sign = find_http_header(req,&sign_params,"sign");
if(sign == NULL)
{
printf("====line:%d,%s\n",__LINE__,"request uri no param sign.");
}
else
{
printf("====line:%d,get request param: sign=[%s]\n",__LINE__,sign);
}
data = find_http_header(req,&sign_params,"data");
if(data == NULL)
{
printf("====line:%d,%s\n",__LINE__,"request uri no param data.");
}
else
{
printf("====line:%d,get request param: data=[%s]\n",__LINE__,data);
}
printf("\n");
struct evbuffer *retbuff = NULL;
retbuff = evbuffer_new();
if(retbuff == NULL)
{
printf("====line:%d,%s\n",__LINE__,"retbuff is null.");
return;
}
evbuffer_add_printf(retbuff,"Receive get request,Thamks for the request!");
evhttp_send_reply(req,HTTP_OK,"Client",retbuff);
evbuffer_free(retbuff);
}
void http_handler_testpost_msg(struct evhttp_request *req,void *arg)
{
if(req == NULL)
{
printf("====line:%d,%s\n",__LINE__,"input param req is null.");
return;
}
char buf[BUF_MAX] = {0};
get_post_message(buf, req);
if(buf == NULL)
{
printf("====line:%d,%s\n",__LINE__,"get_post_message return null.");
return;
}
else
{
printf("====line:%d,request data:%s",__LINE__,buf);
}
struct evbuffer *retbuff = NULL;
retbuff = evbuffer_new();
if(retbuff == NULL)
{
printf("====line:%d,%s\n",__LINE__,"retbuff is null.");
return;
}
evbuffer_add_printf(retbuff,"Receive post request,Thamks for the request!");
evhttp_send_reply(req,HTTP_OK,"Client",retbuff);
evbuffer_free(retbuff);
}
int main()
{
struct evhttp *http_server = NULL;
short http_port = 8081;
char *http_addr = "0.0.0.0";
event_init();
http_server = evhttp_start(http_addr,http_port);
if(http_server == NULL)
{
printf("====line:%d,%s\n",__LINE__,"http server start failed.");
return -1;
}
evhttp_set_timeout(http_server,5);
evhttp_set_cb(http_server,"/me/testpost",http_handler_testpost_msg,NULL);
evhttp_set_cb(http_server,"/me/testget",http_handler_testget_msg,NULL);
event_dispatch();
evhttp_free(http_server);
return 0;
}
代码里注释已经解释很清楚了,编译:
gcc -o http_server http_server.c -levent
执行:
./http_server
利用postman工具,或者curl命令验证结果:
(1)get
命令行输出:
点击右边<>,查看curl命令:
命令行验证curl命令:
(2)post
curl命令:
curl命令行测试:
以上就是基于libevent的http服务端小测试,如有问题,欢迎交流。
[推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,点击立即学习:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)