libevent evhttp使用

本文详细介绍了libevent的evhttp模块使用,包括创建event_base和evhttp、绑定地址和端口、设置处理函数以及事件循环。讲解了如何获取和解析URI、处理HTTP头、设置请求方法限制。此外,还解决了在Windows环境下编译libevent的问题,如类型错误、头文件冲突、内存管理和编码问题。最后提到了libevent的结构体定义、获取对端IP和端口的方法,并给出了libevent在Windows和Linux下的编译步骤。
摘要由CSDN通过智能技术生成

一、libevent evhttp使用
1、基本流程
http服务端使用到的借口函数及流程如下
1)、创建event_base和evhttp
struct event_base *event_base_new(void);
struct evhttp *evhttp_new(struct event_base *base);
2)、绑定地址和端口
int evhttp_bind_socket(struct evhttp *http, const char *address, ev_uint16_t port);
3)、设置处理函数
void evhttp_set_gencb(struct evhttp *http,
    void (*cb)(struct evhttp_request *, void *), void *arg);
4)、派发事件循环
int event_base_dispatch(struct event_base *);

代码:

#include "event2/http.h"
#include "event2/http_struct.h"
#include "event2/event.h"
#include "event2/buffer.h"
#include "event2/dns.h"
#include "event2/thread.h"

#include <stdlib.h>
#include <stdio.h>

void HttpGenericCallback(struct evhttp_request* request, void* arg)
{
    const struct evhttp_uri* evhttp_uri = evhttp_request_get_evhttp_uri(request);
    char url[8192];
    evhttp_uri_join(const_cast<struct evhttp_uri*>(evhttp_uri), url, 8192);

    printf("accept request url:%s\n", url);

    struct evbuffer* evbuf = evbuffer_new();
    if (!evbuf)
    {
        printf("create evbuffer failed!\n");
        return ;
    }

    //HTTP header
        evhttp_add_header(request->output_headers, "Server", "myhttp v1.0");
        evhttp_add_header(request->output_headers, "Content-Type", "text/plain; charset=UTF-8");//utf8
        //evhttp_add_header(request->output_headers, "Content-Type", "text/html");
          evhttp_add_header(request->output_headers, "Access-Control-Allow-Origin", "*");//跨域
        evhttp_add_header(request->output_headers, "Connection", "close");

   evbuffer_add_printf(evbuf, "Server response. Your request url is %s", url);
    evhttp_send_reply(request, HTTP_OK, "OK", evbuf);
    evbuffer_free(evbuf);
}

void specific_handler(struct evhttp_request *req, void *arg)
{
}

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        printf("usage:%s port\n", argv[0]);
        return 1;
    }

    int port = atoi(argv[1]);
    if (port == 0)
    {
        printf("port error:%s\n", argv[1]);
        return 1;
    }

    struct event_base* base = event_base_new();
    if (!base)
    {
        printf("create event_base failed!\n");
        return 1;
    }

    struct evhttp* http = evhttp_new(base);
    if (!http)
    {
        printf("create evhttp failed!\n");
        return 1;
    }

    if (evhttp_bind_socket(http, "0.0.0.0", port) != 0)
    {
        printf("bind socket failed! port:%d\n", port);
        return 1;
    }
    int http_option_timeout = 120; //in seconds
    evhttp_set_timeout(http, http_option_timeout);
    //evhttp_set_allowed_methods( http , EVHTTP_REQ_GET);
        //指定generic callback
    evhttp_set_gencb(http, HttpGenericCallback, NULL);
    //Set a callback for a specified URI
    evhttp_set_cb(http, "/spec", specific_handler, NULL);

    event_base_dispatch(base);
    evhttp_free(http);
    return 0;
}

多线程的Http Server
两种方式:
1、启多个线程,每个子线程持有一个event_base和evhttp,接受请求和处理业务逻辑在同一个子线程中。
2、主线程持有一个event_base和evhttp,主线程接受到请求放入队列,子线程中只处理业务逻辑。
在上面的Http Server中,处理Http请求的回调函数generic_handler和定时器读取文件的回调函数read_file_timer_cb都在同一个event_base的dispatch中,并且都在同一个进程中,使用多线程可以改善程序的性能,下面是一个来自网络的多线程Http Server:
#include <event.h>
#include <evhttp.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
 
int httpserver_bindsocket(int port, int backlog);
int httpserver_start(int port, int nthreads, int backlog);
void* httpserver_Dispatch(void *arg);
void httpserver_GenericHandler(struct evhttp_request *req, void *arg);
void httpserver_ProcessRequest(struct evhttp_request *req);
 
int httpserver_bindsocket(int port, int backlog) {
  int r;
  int nfd;
  nfd = socket(AF_INET, SOCK_STREAM, 0);
  if (nfd < 0) return -1;
 
  int one = 1;
  r = setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(int));
 
  struct sockaddr_in addr;
  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port = htons(port);
 
  r = bind(nfd, (struct sockaddr*)&addr, sizeof(addr));
  if (r < 0) return -1;
  r = listen(nfd, backlog);
  if (r < 0) return -1;
 
  int flags;
  if ((flags = fcntl(nfd, F_GETFL, 0)) < 0
      || fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0)
    return -1;
 
  return nfd;
}
 
int httpserver_start(int port, int nthreads, int backlog) {
  int r, i;
  int nfd = httpserver_bindsocket(port, backlog);
  if (nfd < 0) return -1;
  pthread_t ths[nthreads];
  for (i = 0; i < nthreads; i++) {
    struct event_base *base = event_init();
    if (base == NULL) return -1;
    struct evhttp *httpd = evhttp_new(base);
    if (httpd == NULL) return -1;
    r = evhttp_accept_socket(httpd, nfd);
    if (r != 0) return -1;
    evhttp_set_gencb(httpd, httpserver_GenericHandler, NULL);
    r = pthread_create(&ths[i], NULL, ht
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byxdaz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值