在使用C语言编码时, 有时候需要实现一个HTTP接口, 我们可以选择使用libevent库来实现.
以下代码演示了使用libevent, 并同时支持多线程处理HTTP的请求.
头文件
引入的头文件:
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <event2/http.h>
#include <event2/http_struct.h>
#include <event2/keyvalq_struct.h>
创建多线程监听
创建socket, 使用了APR库.
apr_socket_t* http_socket_create(apr_port_t port, apr_pool_t* pool)
{
apr_status_t rv;
apr_socket_t* socket = NULL;
apr_sockaddr_t* addr;
char msg[246];
do
{
rv = apr_socket_create(&socket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, pool);
if (APR_SUCCESS != rv)
{
apr_strerror(rv, msg, sizeof(msg));
dzlog_fatal("failed to create socket, port:%u, reason:%s", port, msg);
break;
}
rv = apr_sockaddr_info_get(&addr, 0, APR_INET, port, 0, pool);
if (APR_SUCCESS != rv)
{
apr_strerror(rv, msg, sizeof(msg));
dzlog_fatal("apr_sockaddr_info_get failed, reason:%s", msg);
break;
}
apr_socket_opt_set(socket, APR_SO_NONBLOCK, 1);
apr_socket_opt_set(socket, APR_SO_LINGER, 1);
apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1);
rv = apr_socket_bind(socket, addr);
if (APR_SUCCESS != rv)
{
apr_strerror(rv, msg, sizeof(msg));
dzlog_fatal("failed to bind port %u", port);
break;
}
return socket;
} while (0);
if (socket) apr_socket_close(socket);
return NULL;
}
多线程监听:
_server->http_socket = http_socket_create(_server->http_port, _server->pool);
apr_socket_listen(_server->http_socket, 5);
apr_os_sock_get(&fd, _server->http_socket);
for (i = 0; i < _server->http_thread_number; i++)
{
struct event_base* base = event_base_new();
struct evhttp* http = evhttp_new(base);
_server->http_servers[i].base = base;
_server->http_servers[i].http = http;
evhttp_accept_socket(http, fd);
evhttp_set_gencb(http, &http_server_handler, NULL);
apr_thread_create(&_server->http_servers[i].thread, NULL, &http_server_thread, base, _server->pool);
}
线程函数:
static void* APR_THREAD_FUNC http_server_thread(apr_thread_t* thread, void* arg)
{
struct event_base* base = (struct event_base*)arg;
event_base_dispatch(base);
return NULL;
}
HTTP请求入口函数:
static void http_server_handler(struct evhttp_request* req, void* arg)
{
int code;
const struct evhttp_uri* uri = evhttp_request_get_evhttp_uri(req);
if (NULL == uri)
{
dzlog_error("http: evhttp_request_get_evhttp_uri null");
evhttp_send_error(req, HTTP_BADREQUEST, NULL);
return;
}
const char* url = evhttp_uri_get_path(uri);
if (NULL == url)
{
dzlog_error("http: evhttp_uri_get_path fail");
evhttp_send_error(req, HTTP_BADREQUEST, NULL);
return;
}
struct evbuffer* evb = evbuffer_new();
evbuffer_expand(evb, 4 * 1024);
switch (evhttp_request_get_command(req))
{
case EVHTTP_REQ_POST:
{
struct evbuffer* ib;
const char* body;
ib = evhttp_request_get_input_buffer(req);
if (NULL != ib)
{
evbuffer_add(ib, "\0", 1);
body = (const char*)evbuffer_pullup(ib, -1);
cJSON* root = cJSON_Parse(body);
if (NULL == root)
{
dzlog_warn("HTTP: invalid JSON, URL=[%s], BODY=[%s]", url, body);
code = HTTP_EXPECTATIONFAILED;
mdf_set_errcode(evb, ERR_INVALID_JSON);
}
else
{
dzlog_debug("HTTP: Receive 'POST', URL='%s', BODY=%s", url, body);
on_http_post(app, root, evb);
cJSON_Delete(root);
}
}
break;
}
case EVHTTP_REQ_GET:
{
struct evkeyvalq headers = { 0 };
if (0 == evhttp_parse_query_str(evhttp_uri_get_query(evhttp_request_get_evhttp_uri(req)), &headers))
{
code = on_http_get(app, &headers, evb);
evhttp_clear_headers(&headers);
}
break;
}
......
}
evhttp_send_reply(req, code, NULL, evb);
evbuffer_free(evb);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)