evhttp
来源:互联网 发布:苹果扫描软件下载 编辑:程序博客网 时间:2024/05/29 15:54
libevent库使得高并发响应HTTP Server的编写变得很容易。
因此实际中,使用libevent可以为任何应用(如数据库)提供一个HTTP based的网络接口,方便多个clients采用任何支持HTTP protocol的语言与server进行交互
最近将之前用gsoap写的webserver改为使用libevent库。gsoap是为了实现soap协议,如果客户端只调用restful风格的接口的话,用gsoap实现http server有很多多余的东西了,而且处理起来也不太方便。
虽然之前使用过libevent,不过evhttp还是第一次用,还是一如既往的好用。再此简单记录下,方便以后取用。
代码(https://github.com/xuleicode/lb,单线程,多线程。供自己参考)
整个过程包括如下几步:
- 初始化
- 创建HTTP Server
- 指定回调函数(根据情况可指定多个),
- 进入事件循环
- 在回调函数中,可以获取客户端请求(request的HTTP
Header和参数等),进行相应处理后,再将结果发送给客户端(response的HTTP Header和内容)。
#include <evhttp.h>void httpd_handler(struct evhttp_request *req, void *arg);void specific_handler(struct evhttp_request *req, void *arg);int starthttp(){ /* 使用libevent创建HTTP Server */ //初始化event API event_init(); //创建一个http server struct evhttp *httpd; //默认参数 char *httpd_option_listen = "0.0.0.0"; int httpd_option_port = 8080; int httpd_option_daemon = 0; int httpd_option_timeout = 120; //in seconds httpd = evhttp_start(httpd_option_listen, httpd_option_port); evhttp_set_timeout(httpd, httpd_option_timeout); // //evhttp_set_allowed_methods( httpd , EVHTTP_REQ_GET); //指定generic callback evhttp_set_gencb(httpd, httpd_handler, NULL); //Set a callback for a specified URI evhttp_set_cb(httpd, "/spec", specific_handler, NULL); //循环处理events event_dispatch(); evhttp_free(httpd); return 0;}
//linux编译:需要levent库g++ -o myhttpd -Wall -levent myhttpd.cpp
//windwos 下需要添加依赖库ws2_32.libwsock32.liblibevent.liblibevent_core.liblibevent_extras.lib//并且windows下使用libevnet网络时需要//初始化winsocket#ifdef WIN32 WSADATA wsaData; if(WSAStartup(MAKEWORD(2,2) , &wsaData) != 0) { return -1; }#endif//和释放#ifdef WIN32 WSACleanup(); #endif
主要结构体
evhttp_request *req 中包含了http请求的所有内容
struct evkeyvalq *input_headers; //保存客户端请求的HTTP headers(key-value pairs)struct evkeyvalq *output_headers; //保存将要发送到客户端的HTTP headers(key-value pairs)//客户端的ip和portchar *remote_host;u_short remote_port;enum evhttp_request_kind kind; //可以是EVHTTP_REQUEST或EVHTTP_RESPONSE//enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE }; enum evhttp_cmd_type type; //可以是EVHTTP_REQ_GET, EVHTTP_REQ_POST或EVHTTP_REQ_HEAD等,详见最后char *uri; //客户端请求的urichar major; //HTTP major numberchar minor; //HTTP major numberint response_code; //HTTP response codechar *response_code_line; //readable responsestruct evbuffer *input_buffer; //客户端POST的数据struct evbuffer *output_buffer; //输出到客户端的数据...//还有一些回调函数指针
保存参数的结构体
/* * Key-Value pairs. Can be used for HTTP headers but also for * query argument parsing. */struct evkeyval { TAILQ_ENTRY(evkeyval) next; char *key; char *value;};
宏TAILQ_ENTRY(evkeyval)被定义为:#define TAILQ_ENTRY(type) struct { struct type *tqe_next; //next element struct type **tqe_prev; //address of previous next element }
buffer结构体
//buffer.hstruct evbuffer#ifdef EVENT_IN_DOXYGEN_{}#endif;//evbuffer-internal.h文件 struct evbuffer_chain; struct evbuffer { struct evbuffer_chain *first; struct evbuffer_chain *last; //二级指针。使用*last_with_datap时,指向的是链表中最后一个有数据的evbuffer_chain。 //所以last_with_datap存储的是倒数第二个evbuffer_chain的next成员地址。 //一开始buffer->last_with_datap = &buffer->first;此时first为NULL。所以当链表没有节点时 //*last_with_datap为NULL。当只有一个节点时*last_with_datap就是first。 struct evbuffer_chain **last_with_datap; size_t total_len;//链表中所有chain的总字节数 ... }; struct evbuffer_chain { struct evbuffer_chain *next; size_t buffer_len;//buffer的大小 //错开不使用的空间。该成员的值一般等于0 ev_off_t misalign; //evbuffer_chain已存数据的字节数 //所以要从buffer + misalign + off的位置开始写入数据 size_t off; ... unsigned char *buffer; };
另外定义宏方便获取evbuffer中保存的内容和大小:
#define EVBUFFER_LENGTH(x) (x)->off #define EVBUFFER_DATA(x) (x)->buffer
例如,获取客户端POST数据的内容和大小:
EVBUFFER_DATA(res->input_buffer); EVBUFFER_LENGTH(res->input_buffer);//这个和res->body_size相同
另外struct evbuffer用如下函数创建添加和释放:
struct evbuffer *buf; buf = evbuffer_new(); //往buffer中添加内容 evbuffer_add_printf(buf, "I got it! you just requested: %s\n", req->uri); //Append a formatted string to the end of an evbuffer. //将内容输出到客户端 evhttp_send_reply(req, HTTP_OK, "OK", buf); //释放掉buf evbuffer_free(buf);
关键函数
获取客户端请求的URI
//使用req->uri//或使用函数const char *evhttp_request_uri(struct evhttp_request *req);//即(evhttp_request_uri(req);)。
对获取的URI进行解析和其他操作
使用函数
void evhttp_parse_query(const char *uri, struct evkeyvalq *args);
可对uri的参数进行解析,结果保存在struct evkeyvalq的key-value pairs中,例如:
char *uri = "http://foo.com/?id=1&infor=hello"; struct evkeyvalq args; evhttp_parse_query(uri, &args); //然后通过evhttp_find_header等函数获取各个参数及对应的值 evhttp_find_header(&args, "id"); //得到test evhttp_find_header(&args, "infor"); //得到some thing
如下两个函数对URI进行encode和decode:
char *evhttp_encode_uri(const char *uri); char *evhttp_decode_uri(const char *uri);
URI encode的结果是所有非alphanumeric及-_的字符都被类似于%和一个2位16进制字符替换(其中空格被+号替换)。如上两个函数返回的字符串需要free掉。
Escape特殊的HTML字符
char *evhttp_htmlescape(const char *html);
特殊字符:&被替换为&;”被替换为";’被替换为'; <被替换为<;>被替换为>。该函数返回的字符串需要free掉。
处理HTTP headers相关的函数
HTTP headers保存在req的input_headers中,这个是struct evkeyvalq 的结构体(key-value pairs),使用如下函数可对其进行修改:
const char *evhttp_find_header(const struct evkeyvalq *, const char *);int evhttp_remove_header(struct evkeyvalq *, const char *);int evhttp_add_header(struct evkeyvalq *, const char *, const char *);void evhttp_clear_headers(struct evkeyvalq *);
设定只识别get请求,
evhttp_set_allowed_methods( httpd , EVHTTP_REQ_GET);
设置后,只处理get请求,其他请求返回405 Method not allowed,我自己使用的时候发现返回的是501 Not Implemented
请求类型如下:
enum evhttp_cmd_type { EVHTTP_REQ_GET = 1 << 0, EVHTTP_REQ_POST = 1 << 1, EVHTTP_REQ_HEAD = 1 << 2, EVHTTP_REQ_PUT = 1 << 3, EVHTTP_REQ_DELETE = 1 << 4, EVHTTP_REQ_OPTIONS = 1 << 5, EVHTTP_REQ_TRACE = 1 << 6, EVHTTP_REQ_CONNECT = 1 << 7, EVHTTP_REQ_PATCH = 1 << 8};
- evhttp
- evhttp实现的http服务器
- evhttp处理POST请求的技巧
- libevent evhttp学习——http客户端
- libevent evhttp学习——http服务端
- libevent evhttp学习——http客户端
- libevent evhttp学习——http服务端
- 64位centos6.7安装mysql-5.7.9-linux-glibc2.5-x86_64.tar.gz
- 利用 Hexo + Github Pages 搭建免费博客
- Caffe与cudnn 6.0 的兼容性问题 CUDNN_STATUS_BAD_PARAM
- Registry Winner(顶级系统注册表优化专家)官方破解版V7.0.12.15下载 | 无需registry winner注册码
- Java基础之hashCode()方法
- evhttp
- LeetCode算法第三题
- POJ-1651 Multiplication Puzzle (区间DP)
- 深入Java关键字null
- czl的知识点整理5——单调队列
- 安装第三方库
- Pandas tips
- iOS11 打开系统相册 导航栏透明 且列表的frame也不对
- 【MYSQL】win7安装mysql-5.7.10绿色版