基于libevent的http服务器实现
基于libevent的http服务器实现
//libevent的http服务器简单实现方式
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
//for struct evkeyvalq
#include <sys/queue.h>
#include <event.h>
#include <event2/http.h>
#include <event2/http_struct.h>
#include <event2/http_compat.h>
#include <event2/util.h>
#include <signal.h>
#define LOG_INFO printf
#define LOG_DBG printf
#define LOG_ERR printf
#define MYHTTPD_SIGNATURE "httpd v 0.0.1"
//处理模块
void httpd_handler(struct evhttp_request *req, void *arg) {
char output[2048] = "\0";
char tmp[1024];
//获取客户端请求的URI(使用evhttp_request_uri或直接req->uri)
const char *uri;
uri = evhttp_request_uri(req);
sprintf(tmp, "uri=%s\n", uri);
strcat(output, tmp);
sprintf(tmp, "uri=%s\n", req->uri);
strcat(output, tmp);
//decoded uri
char *decoded_uri;
decoded_uri = evhttp_decode_uri(uri);
sprintf(tmp, "decoded_uri=%s\n", decoded_uri);
strcat(output, tmp);
//解析URI的参数(即GET方法的参数)
struct evkeyvalq params;
//将URL数据封装成key-value格式,q=value1, s=value2
evhttp_parse_query(decoded_uri, ¶ms);
//得到q所对应的value
sprintf(tmp, "q=%s\n", evhttp_find_header(¶ms, "q"));
strcat(output, tmp);
//得到s所对应的value
sprintf(tmp, "s=%s\n", evhttp_find_header(¶ms, "s"));
strcat(output, tmp);
free(decoded_uri);
//获取POST方法的数据
char *post_data = (char *) EVBUFFER_DATA(req->input_buffer);
sprintf(tmp, "post_data=%s\n", post_data);
strcat(output, tmp);
/* 输出到客户端 */
//HTTP header
evhttp_add_header(req->output_headers, "Server", MYHTTPD_SIGNATURE);
evhttp_add_header(req->output_headers, "Content-Type", "text/plain; charset=UTF-8");
evhttp_add_header(req->output_headers, "Connection", "close");
//输出的内容
struct evbuffer *buf;
buf = evbuffer_new();
evbuffer_add_printf(buf, "It works!\n%s\n", output);
evhttp_send_reply(req, HTTP_OK, "OK", buf);
evbuffer_free(buf);
}
void show_help() {
char *help = "http://localhost:8080\n"
"-l <ip_addr> interface to listen on, default is 0.0.0.0\n"
"-p <num> port number to listen on, default is 1984\n"
"-d run as a deamon\n"
"-t <second> timeout for a http request, default is 120 seconds\n"
"-h print this help and exit\n"
"\n";
fprintf(stderr,"%s",help);
}
//当向进程发出SIGTERM/SIGHUP/SIGINT/SIGQUIT的时候,终止event的事件侦听循环
void signal_handler(int sig) {
switch (sig) {
case SIGTERM:
case SIGHUP:
case SIGQUIT:
case SIGINT:
event_loopbreak(); //终止侦听event_dispatch()的事件侦听循环,执行之后的代码
break;
}
}
int main(int argc, char *argv[]) {
//自定义信号处理函数
signal(SIGHUP , signal_handler);
signal(SIGTERM , signal_handler);
signal(SIGINT , signal_handler);
signal(SIGQUIT , signal_handler);
//默认参数
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
LOG_INFO("http server start %s:%d\n", httpd_option_listen, httpd_option_port);
//获取参数
int c;
while ((c = getopt(argc, argv, "l:p:dt:h")) != -1) {
switch (c) {
case 'l' :
httpd_option_listen = optarg;
break;
case 'p' :
httpd_option_port = atoi(optarg);
break;
case 'd' :
httpd_option_daemon = 1;
break;
case 't' :
httpd_option_timeout = atoi(optarg);
break;
case 'h' :
default :
show_help();
exit(EXIT_SUCCESS);
}
}
//判断是否设置了-d,以daemon运行
if (httpd_option_daemon) {
pid_t pid;
pid = fork();
if (pid < 0) {
perror("fork failed");
exit(EXIT_FAILURE);
}
if (pid > 0) {
//生成子进程成功,退出父进程
exit(EXIT_SUCCESS);
}
}
/* 使用libevent创建HTTP Server */
//初始化event API
event_init();
//创建一个http server
struct evhttp *httpd;
httpd = evhttp_start(httpd_option_listen, httpd_option_port);
evhttp_set_timeout(httpd, httpd_option_timeout);
//指定generic callback
evhttp_set_gencb(httpd, httpd_handler, NULL);
//也可以为特定的URI指定callback
//evhttp_set_cb(httpd, "/", specific_handler, NULL);
//开始事件监听,分发
event_dispatch();
//释放资源
evhttp_free(httpd);
return 0;
}
更多编程内容见公众号 xutopia77,有更多系列的libevent文章介绍