工作,学习,生活,这里将会有一些记录. 备用域名:http://meisw.51099.com 注册 | 登陆
浏览模式: 标准 | 列表分类:c

libevent 建立最简单的 webserver

libevent是一个事件触发的网络库,适用于windows、linux、bsd等多种平台,内部使用select、epoll、kqueue等系统调用管理事件机制。分布式缓存memcached据说也是libevent based,而且libevent在使用上可以做到跨平台,而且根据libevent官方网站上公布的数据统计,似乎也有着非凡的性能。

  更多的信息可以去这里了解:http://baike.baidu.com/view/1590523.htm

  先下载 libevent,官方地址是:http://monkey.org/~provos/libevent/,在下面有下载地址列表,我这里下载了1.4.10-stable这个版本。

  安装 libevnet:

#wget http://monkey.org/~provos/libevent-1.4.10-stable.tar.gz
#tar zxvf libevent-1.4.10-stable.tar.gz
#cd libevent-1.4.10-stable
#./configure
#make
#make install

  接下来看这个 c 语言示例程序 my_xhttpd.c:

 

#include <sys/types.h>
#include <sys/time.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <assert.h>
#include <signal.h>
#include <stdbool.h>
#include <err.h>

// 引入 libevent 头文件
#include <event.h>
#include <evhttp.h>

// 请求处理模块
void http_handler(struct evhttp_request *req, void *arg)
{
  struct evbuffer *buf;
  buf = evbuffer_new();

  // 分析URL参数
  char *decode_uri = strdup((char*) evhttp_request_uri(req));
  struct evkeyvalq http_query;
  evhttp_parse_query(decode_uri, &http_query);
  free(decode_uri);

  // 从http头中获取参数,如果是GET传输,这里就可以取得action的值
  const char *request_value = evhttp_find_header(&http_query, "data");

  // 返回给浏览器的信息
  evhttp_add_header(req->output_headers, "Content-Type", 
"text/html; charset=UTF-8");
  evhttp_add_header(req->output_headers, "Server", "my_httpd");
  //evhttp_add_header(req->output_headers, "Connection", "keep-alive");
  evhttp_add_header(req->output_headers, "Connection", "close");

  // 将要输出的值加入到输出缓存中
  if(request_value != NULL) {
    evbuffer_add_printf(buf, "%s", request_value);
  } else {
    evbuffer_add_printf(buf, "%s", "no error.");
  }

  // 输出内容到浏览器
  evhttp_send_reply(req, HTTP_OK, "OK", buf);

  // 内存释放
  evhttp_clear_headers(&http_query);
  evbuffer_free(buf);
}

int main(int argc, char **argv)
{
  char *host_ip = "0.0.0.0";
  int host_port = 8080;
  int timeout = 3;

  struct evhttp *httpd;

  event_init();

  // 绑定本机ip和端口,在访问时一定要把8080端口开放出来
  httpd = evhttp_start(host_ip, host_port);

  if (httpd == NULL) {
    fprintf(stderr, "Error: Unable to listen on %s:%d\n\n", host_ip, host_port);		
    exit(1);		
  }

  // 设置请求超时时间
  evhttp_set_timeout(httpd, timeout);

  // 设置请求的处理函数
  evhttp_set_gencb(httpd, http_handler, NULL);

  event_dispatch();

  evhttp_free(httpd);

  return 0;
}

  编译源码:gcc -o my_httpd my_httpd.c -L/usr/local/lib/ -levent -I/usr/local/include/ -lz -lbz2 -lrt -lpthread -lm -lc -O2

  编译成功后就会在当前目录生成一个 my_httpd 可执行文件。

  放在后台启动:./my_httpd >/dev/null 2>&1 &

  打开浏览器,输入访问地址,如图:

  这只是个用来学习的简单示例,但 libevent 功能强大,有很多可以值的学习的地方。