关于libevent+http服务端的一个样例

#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;
				if(errno != ECHILD)
					log_error("wait child failed \"%d: %s\"", errno, strerror(errno));
				break;
			case 0:
				log_info("child still running");
				break;
			default:
				log_info("wait child 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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值