libevent 使用实现http 服务

单线程

#include <stdio.h>
#include <stdlib.h>
#include <string.h>  //for strcat
#include <unistd.h>  //for getopt, fork
// for struct evkeyvalq
#include <event.h>
#include <sys/queue.h>
// for http
//#include <evhttp.h>
#include <event2/http.h>
#include <event2/http_compat.h>
#include <event2/http_struct.h>
#include <event2/util.h>
#include <signal.h>

#define MYHTTPD_SIGNATURE "myhttpd v 0.0.1"
//处理模块
void httpd_handler(struct evhttp_request *req, void *arg) {
  char output[2048] = "\0";
  char tmp[1024];
   struct evbuffer * input = evhttp_request_get_input_buffer(req);
	int len = evbuffer_get_length(input);
    printf("evbuffer_get_length len = %d\n", len); 
	printf("evhttp_find_header Content-Length = %s\n", evhttp_find_header(req->input_headers,"Content-Length"));
	printf("Content-Type = %s\n", evhttp_find_header(req->input_headers,"Content-Type"));

  //获取客户端请求的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, &params);
  //得到q所对应的value
  sprintf(tmp, "q=%s\n", evhttp_find_header(&params, "q"));
  strcat(output, tmp);
  //得到s所对应的value
  sprintf(tmp, "s=%s\n", evhttp_find_header(&params, "s"));
  strcat(output, tmp);
  free(decoded_uri);
  //获取POST方法的数据
  char *post_data = (char *) EVBUFFER_DATA(req->input_buffer);
  printf("post data = %s\n", post_data);
  printf("output = %s\n", output);
  /*
  具体的:可以根据GET/POST的参数执行相应操作,然后将结果输出
  ...
  */
  /* 输出到客户端 */
  // 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");
  evhttp_add_header(req->output_headers, "User-Agent", "curl");
  //输出的内容
  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);
}

static struct bufferevent *
https_bev(struct event_base *base, void *arg)
{
    printf("new cient connect!\n");
}
//当向进程发出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
  
  /* 使用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_bevcb(httpd, https_bev, NULL);
   //evhttp_set_cb(httpd, "/datas", httpd_handler, NULL);
  //循环处理events
  event_dispatch();
  evhttp_free(httpd);
  return 0;
}

多线程

#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>  //for strcat
#include <unistd.h>  //for getopt, fork
// for struct evkeyvalq
#include <event.h>
#include <sys/queue.h>
// for http
//#include <evhttp.h>
#include <event2/http.h>
#include <event2/http_compat.h>
#include <event2/http_struct.h>
#include <event2/util.h>
#include <signal.h>

#define MYHTTPD_SIGNATURE "myhttpd v 0.0.1"
//处理模块
void httpd_handler(struct evhttp_request *req, void *arg) {
  char output[2048] = "\0";
  char tmp[1024];
  struct evbuffer *input = evhttp_request_get_input_buffer(req);
  int len = evbuffer_get_length(input);
  printf("pthread [%ld]\n", pthread_self());
  printf("evbuffer_get_length len = %d\n", len);
  printf("evhttp_find_header Content-Length = %s\n",
         evhttp_find_header(req->input_headers, "Content-Length"));
  printf("Content-Type = %s\n",
         evhttp_find_header(req->input_headers, "Content-Type"));

  //获取客户端请求的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, &params);
  //得到q所对应的value
  sprintf(tmp, "q=%s\n", evhttp_find_header(&params, "q"));
  strcat(output, tmp);
  //得到s所对应的value
  sprintf(tmp, "s=%s\n", evhttp_find_header(&params, "s"));
  strcat(output, tmp);
  free(decoded_uri);
  //获取POST方法的数据
  char *post_data = (char *) EVBUFFER_DATA(req->input_buffer);
  printf("post data = %s\n", post_data);
  printf("output = %s\n", output);
  /*
  具体的:可以根据GET/POST的参数执行相应操作,然后将结果输出
  ...
  */
  /* 输出到客户端 */
  // 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");
  evhttp_add_header(req->output_headers, "User-Agent", "curl");
  //输出的内容
  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);
}

//当向进程发出SIGTERM/SIGHUP/SIGINT/SIGQUIT的时候,终止event的事件侦听循环
void signal_handler(int sig) {
  switch (sig) {
    case SIGTERM:
    case SIGHUP:
    case SIGQUIT:
    case SIGINT:
        exit(-1);
      break;
  }
}

int http_init(int port) {
  int nfd = socket(AF_INET, SOCK_STREAM, 0);
  if (nfd < 0) {
    return -1;
  }

  const int one = 1;
  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);

  if (bind(nfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    return -1;
  }

  if (listen(nfd, 128) < 0) {
    return -1;
  }

  int flags = 0;
  if ((flags = fcntl(nfd, F_GETFL, 0)) < 0 ||
      fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
    return -1;
  }

  return nfd;
}

void *worker_func(void *arg) {
  printf("start pthread [%ld]\n", pthread_self());
  event_base_dispatch((struct event_base *) arg);
}

#define MAX_WORK_PTHREAD 3

int main(int argc, char *argv[]) {
  //默认参数
  char *httpd_option_listen = "0.0.0.0";
  int httpd_option_port = 8080;
  int httpd_option_timeout = 120;  // in seconds

  pthread_t thread_list[MAX_WORK_PTHREAD];
  struct event_base *bases[MAX_WORK_PTHREAD];
  struct evhttp *httpds[MAX_WORK_PTHREAD];

  signal(SIGHUP, signal_handler);
  signal(SIGTERM, signal_handler);
  signal(SIGINT, signal_handler);
  signal(SIGQUIT, signal_handler);
  int fd = http_init(httpd_option_port);
  if (fd < 0) {
    return -1;
  }

  for (int i = 0; i < MAX_WORK_PTHREAD; i++) {
    bases[i] = event_init();
    httpds[i] = evhttp_new(bases[i]);
    if (evhttp_accept_socket(httpds[i], fd) != 0) {
      return -1;
    }
    evhttp_set_timeout(httpds[i], httpd_option_timeout);
    evhttp_set_gencb(httpds[i], httpd_handler, NULL);
    if (pthread_create(&thread_list[i], NULL, worker_func, (void *) bases[i]) !=
        0) {
      return -1;
    }
  }
  for (int i = 0; i < MAX_WORK_PTHREAD; ++i) {
    pthread_join(thread_list[i], NULL);
  }

  for (int i = 0; i < MAX_WORK_PTHREAD; i++) {
    event_base_free(bases[i]);
    evhttp_free(httpds[i]);
  }
  return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libevent是一个开源的事件驱动库,可以用来开发高并发的网络应用程序。下面是一个使用libevent实现的简单的HTTP服务器示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <event2/event.h> #include <event2/http.h> void http_cb(struct evhttp_request *req, void *arg) { const char *uri = evhttp_request_get_uri(req); printf("Request URI: %s\n", uri); struct evbuffer *evb = evbuffer_new(); if (evb == NULL) { fprintf(stderr, "Failed to create evbuffer\n"); evhttp_send_error(req, HTTP_INTERNAL, "Internal Server Error"); return; } evbuffer_add_printf(evb, "Hello World!"); evhttp_send_reply(req, HTTP_OK, "OK", evb); evbuffer_free(evb); } int main(int argc, char *argv[]) { struct event_base *base = event_base_new(); if (base == NULL) { fprintf(stderr, "Failed to create event_base: %s\n", strerror(errno)); return EXIT_FAILURE; } struct evhttp *httpd = evhttp_new(base); if (httpd == NULL) { fprintf(stderr, "Failed to create evhttp: %s\n", strerror(errno)); return EXIT_FAILURE; } if (evhttp_bind_socket(httpd, "0.0.0.0", 8080) != 0) { fprintf(stderr, "Failed to bind to 0.0.0.0:8080: %s\n", strerror(errno)); return EXIT_FAILURE; } evhttp_set_cb(httpd, "/", http_cb, NULL); printf("HTTP server started on 0.0.0.0:8080\n"); event_base_dispatch(base); evhttp_free(httpd); event_base_free(base); return EXIT_SUCCESS; } ``` 这个HTTP服务器监听本地8080端口,处理根路径的请求,返回"Hello World!"。可以使用curl命令测试: ``` $ curl http://localhost:8080/ Hello World! ``` 这只是一个简单的示例,实际的HTTP服务器需要更多的功能和处理逻辑。libevent提供了丰富的API和事件处理机制,可以很方便地实现高并发、高性能的网络应用程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值