关于libevent+http服务端的一个样例
2015-09-10 17:32
183 查看
libevent对于多进程/多线程支持不好, 以下只是一个多进程的简单样例.
#include <sys/wait.h> #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <stdint.h> #include <stdbool.h> #include <libgen.h> #include <signal.h> #include <event.h> #include <evhttp.h> #include <event2/event.h> #include <event2/thread.h> #include <event2/buffer.h> #include <event2/bufferevent.h> #include <event2/util.h> #include <event2/dns.h> #include <event2/http.h> #include <event2/rpc.h> #include <jansson.h> #include "log.h" static void fork_parent_process(struct evhttp_request *req, void *arg) { struct evkeyvalq *headers = NULL; struct evkeyval *header = NULL; struct evbuffer *req_evb = NULL; struct evbuffer *res_evb = NULL; int ret = 0; int req_len = 0; char *req_buf = NULL; char *res_buf = NULL; json_t *req_json = NULL; json_t *res_json = NULL; if(evhttp_request_get_command(req) != EVHTTP_REQ_POST) { log_error("jsonrpc_request_cb EVHTTP_REQ_POST failed"); goto EndP; } headers = evhttp_request_get_input_headers(req); for (header = headers->tqh_first; header; header = header->next.tqe_next) log_debug("%s: %s", header->key, header->value); req_evb = evhttp_request_get_input_buffer(req); req_len = evbuffer_get_length(req_evb); req_buf = (char*)malloc(req_len+1); if(!req_buf) { log_error("malloc failed"); goto EndP; } memset(req_buf, 0, req_len+1); ret = evbuffer_remove(req_evb, req_buf, req_len); if(ret != req_len) { log_error("evbuffer_copyout failed"); goto EndP; } req_buf[req_len] = 0; log_info("Request: %s", req_buf); req_json = json_loadb((const char *)req_buf, req_len, 0, NULL); if(!req_json) { log_error("jsonrpc_request_cb json_loadb failed: %s", strerror(errno)); goto EndP; } json_t *method_json = json_object_get(req_json, "method"); char *method_buf = (char*)json_string_value(method_json); if(!method_json || !method_buf || strncasecmp(method_buf, "jsonrpc", 7)) { log_error("jsonrpc_request_cb method failed"); goto EndP; } evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/json; charset=UTF-8"); evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "keep-alive"); res_json = json_pack("{ s:s, s:s, s:s }", "jsonrpc", "2.0", "result", "succeed", "id", "1"); if(!res_json) { log_error("jsonrpc_request_cb json_pack failed: %s", strerror(errno)); goto EndP; } res_buf = json_dumps(res_json, 0); if(!res_buf) { log_error("jsonrpc_request_cb json_dunmps failed: %s", strerror(errno)); goto EndP; } res_evb = evbuffer_new(); if(!res_evb) { log_error("jsonrpc_request_cb evbuffer_new failed: %s", strerror(errno)); goto EndP; } evbuffer_add_printf(res_evb, "%s", res_buf); log_info("Response: %s", res_buf); evhttp_send_reply(req, HTTP_OK, "OK", res_evb); if(res_evb) evbuffer_free(res_evb); if(res_buf) free(res_buf); if(res_json) json_decref(res_json); if(req_json) json_decref(req_json); if(req_buf) free(req_buf); return; EndP: evhttp_send_error(req, HTTP_BADMETHOD, "BAD METHOD"); if(res_evb) evbuffer_free(res_evb); if(res_buf) free(res_buf); if(res_json) json_decref(res_json); if(req_json) json_decref(req_json); if(req_buf) free(req_buf); return; } static void fork_child_process(struct evhttp_request *req, void *arg) { if(evhttp_request_get_command(req) != EVHTTP_REQ_POST) { log_error("jsonrpc_request_cb EVHTTP_REQ_POST failed"); goto EndP; } exit(EXIT_SUCCESS); EndP: exit(EXIT_FAILURE); } static void jsonrpc_request_cb(struct evhttp_request *req, void *arg) { pid_t pid = fork(); switch(pid) { case -1: log_error("fork child pid failed: %s", strerror(errno)); break; case 0: log_info("fork child pid succeed: %d", getpid()); fork_child_process(req, arg); break; default: log_info("fork parent pid succeed: %d", getpid()); fork_parent_process(req, arg); break; } } static void default_request_cb(struct evhttp_request *req, void *arg) { evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "text/plain; charset=UTF-8"); evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "close"); evhttp_send_error(req, HTTP_NOTFOUND, "NOT FOUND"); } static void chld_evsignal_cb(evutil_socket_t fd, short event, void *arg) { int status = -1; pid_t pid = -1; log_info("chld signal: %d", SIGCHLD); do{ pid = waitpid(-1, &status, WNOHANG); switch(pid) { case -1: if(errno == EINTR) continue; log_error("wait chld pid failed: %s", strerror(errno)); break; case 0: log_info("wait chld pid succeed: %d", pid); break; default: log_info("wait chld pid succeed: %d", pid); break; } }while(pid > 0); } static void term_evsignal_cb(evutil_socket_t fd, short event, void *arg) { struct event_base *base = arg; struct timeval tv = { 1, 0 }; log_info("term signal: %d", SIGINT); event_base_loopexit(base, &tv); } static void alrm_evsignal_cb(evutil_socket_t fd, short event, void *arg) { //struct event *signal_alrm = arg; log_info("alrm signal: %d", SIGALRM); //event_del(signal_alrm); } static void cycle_timout_cb(evutil_socket_t fd, short event, void *arg) { struct timeval tv = {1, 0}; log_info("cycle timeout callback"); event_add(*(struct event**)arg, &tv); } int main(int argc, char *argv[]) { int ret = 0; char *server_ip = "0.0.0.0"; unsigned short server_port = 1990; struct event_base *base = NULL; struct evhttp *http = NULL; struct evhttp_bound_socket *handle = NULL; evutil_socket_t server_fd = -1; struct event *timeout = NULL; struct event *signal_int = NULL; struct event signal_chld; struct event signal_alrm; log_open(basename(argv[0]), 1); base = event_base_new(); if(!base) { log_error("event_base_new failed: %s", strerror(errno)); goto ErrP; } struct timeval tv = {1, 0}; timeout = event_new(base, -1, 0, cycle_timout_cb, (void*)&timeout); if(!timeout) { log_error("evtimer_new failed: %s", strerror(errno)); goto ErrP; } event_add(timeout, &tv); signal_int = event_new(base, SIGINT, EV_SIGNAL|EV_PERSIST, term_evsignal_cb, (void *)base); if(!signal_int) { log_error("evsignal_new failed: %s", strerror(errno)); goto ErrP; } event_add(signal_int, NULL); ret = event_assign(&signal_chld, base, SIGCHLD, EV_SIGNAL|EV_PERSIST, chld_evsignal_cb, (void *)&signal_chld); if(ret != 0) { log_error("evsignal_assign failed: %s", strerror(errno)); goto ErrP; } event_add(&signal_chld, NULL); ret = event_assign(&signal_alrm, base, SIGALRM, EV_SIGNAL|EV_PERSIST, alrm_evsignal_cb, (void *)&signal_alrm); if(ret != 0) { log_error("evsignal_assign failed: %s", strerror(errno)); goto ErrP; } event_add(&signal_alrm, NULL); http = evhttp_new(base); if(!http) { log_error("evhttp_new failed: %s", strerror(errno)); goto ErrP; } handle = evhttp_bind_socket_with_handle(http, server_ip, server_port); if(!handle) { log_error("evhttp_bind_socket_with_handle failed: %s", strerror(errno)); goto ErrP; } server_fd = evhttp_bound_socket_get_fd(handle); log_info("evhttp_bind_socket_with_handle succeed: %d", server_fd); evhttp_set_timeout(http, 120); evhttp_set_cb(http, "/jsonrpc", jsonrpc_request_cb, &base); evhttp_set_gencb(http, default_request_cb, &base); event_base_dispatch(base); if(http) evhttp_free(http); if(signal_int) event_free(signal_int); if(timeout) event_free(timeout); if(base) event_base_free(base); log_close(); return 0; ErrP: if(http) evhttp_free(http); if(signal_int) event_free(signal_int); if(timeout) event_free(timeout); if(base) event_base_free(base); log_close(); return -1; }
相关文章推荐
- http协议
- android 网络请求 开源框架
- android 监听网络变化 多处做出监听处理
- Http请求框架 okHttp 简单使用介绍
- Linux网络编程--select()和pselect()函数
- android6.0SDK中删除HttpClient的相关类的解决方法
- ZOJ 3229 Shoot the Bullet 有源汇上下界网络流 最大流
- HTTP请求详解
- 从贝叶斯方法谈到贝叶斯网络
- ZOJ 2314 Reactor Cooling 无源汇上下界网络流 可行流
- 构造HTTP请求Header实现“伪造来源IP”
- MCC(移动国家码)和 MNC(移动网络码)
- HTTP/2 常见问题回答
- 【Http】HTTP报文结构及请求数据大小
- U3D 网络库实现通信 基于Warensoft Unity3d
- HTTP协议详解
- 异构网络
- [置顶] Linux网络编程--IO模型基础
- Android HttpClient post MultipartEntity - Android 上传文件
- TCP的数据流——滑动窗口,拥塞窗口,慢启动,Nagle算法,经受时延的确认等