您的位置:首页 > 理论基础 > 计算机网络

关于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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: