用libevent构建一个http server非常方便,可参考libevent(六)http server。

主要涉及的一个结构体是evhttp:

struct evhttp {
/* Next vhost, if this is a vhost. */
TAILQ_ENTRY(evhttp) next_vhost; /* All listeners for this host */
TAILQ_HEAD(boundq, evhttp_bound_socket) sockets; TAILQ_HEAD(httpcbq, evhttp_cb) callbacks; /* All live connections on this host. */
struct evconq connections; TAILQ_HEAD(vhostsq, evhttp) virtualhosts; TAILQ_HEAD(aliasq, evhttp_server_alias) aliases; /* NULL if this server is not a vhost */
char *vhost_pattern; int timeout; size_t default_max_headers_size;
ev_uint64_t default_max_body_size; /* Bitmask of all HTTP methods that we accept and pass to user
* callbacks. */
ev_uint16_t allowed_methods; /* Fallback callback if all the other callbacks for this connection
don't match. */
void (*gencb)(struct evhttp_request *req, void *);
void *gencbarg; struct event_base *base;
};

值得关注的有两个成员:
  callbacks,一个链表,存放用户定义的回调函数
  connections,一个链表,存放所有连接,每个连接对应一个evhttp_connection

evhttp_connection结构如下:

/* A client or server connection. */
struct evhttp_connection {
/* we use this tailq only if this connection was created for an http
* server */
TAILQ_ENTRY(evhttp_connection) next; evutil_socket_t fd;
struct bufferevent *bufev; struct event retry_ev; /* for retrying connects */ char *bind_address; /* address to use for binding the src */
u_short bind_port; /* local port for binding the src */ char *address; /* address to connect to */
u_short port; size_t max_headers_size;
ev_uint64_t max_body_size; int flags;
#define EVHTTP_CON_INCOMING 0x0001 /* only one request on it ever */
#define EVHTTP_CON_OUTGOING 0x0002 /* multiple requests possible */
#define EVHTTP_CON_CLOSEDETECT 0x0004 /* detecting if persistent close */ int timeout; /* timeout in seconds for events */
int retry_cnt; /* retry count */
int retry_max; /* maximum number of retries */ enum evhttp_connection_state state; /* for server connections, the http server they are connected with */
struct evhttp *http_server; TAILQ_HEAD(evcon_requestq, evhttp_request) requests; void (*cb)(struct evhttp_connection *, void *);
void *cb_arg; void (*closecb)(struct evhttp_connection *, void *);
void *closecb_arg; struct deferred_cb read_more_deferred_cb; struct event_base *base;
struct evdns_base *dns_base;
};

值得关注的成员有两个:
  bufev,对应一个bufferevent
  requests,一个链表,存放该连接上的所有请求,每个请求对应evhttp_request

evhttp_request结构如下:

struct evhttp_request {
#if defined(TAILQ_ENTRY)
TAILQ_ENTRY(evhttp_request) next;
#else
struct {
struct evhttp_request *tqe_next;
struct evhttp_request **tqe_prev;
} next;
#endif /* the connection object that this request belongs to */
struct evhttp_connection *evcon;
int flags;
/** The request obj owns the evhttp connection and needs to free it */
#define EVHTTP_REQ_OWN_CONNECTION 0x0001
/** Request was made via a proxy */
#define EVHTTP_PROXY_REQUEST 0x0002
/** The request object is owned by the user; the user must free it */
#define EVHTTP_USER_OWNED 0x0004
/** The request will be used again upstack; freeing must be deferred */
#define EVHTTP_REQ_DEFER_FREE 0x0008
/** The request should be freed upstack */
#define EVHTTP_REQ_NEEDS_FREE 0x0010 struct evkeyvalq *input_headers;
struct evkeyvalq *output_headers; /* address of the remote host and the port connection came from */
char *remote_host;
ev_uint16_t remote_port; /* cache of the hostname for evhttp_request_get_host */
char *host_cache; enum evhttp_request_kind kind;
enum evhttp_cmd_type type; size_t headers_size;
size_t body_size; char *uri; /* uri after HTTP request was parsed */
struct evhttp_uri *uri_elems; /* uri elements */ char major; /* HTTP Major number */
char minor; /* HTTP Minor number */ int response_code; /* HTTP Response code */
char *response_code_line; /* Readable response */ struct evbuffer *input_buffer; /* read data */
ev_int64_t ntoread;
unsigned chunked:, /* a chunked request */
userdone:; /* the user has sent all data */ struct evbuffer *output_buffer; /* outgoing post or data */ /* Callback */
void (*cb)(struct evhttp_request *, void *);
void *cb_arg; /*
* Chunked data callback - call for each completed chunk if
* specified. If not specified, all the data is delivered via
* the regular callback.
*/
void (*chunk_cb)(struct evhttp_request *, void *);
}; 

值得注意的是:
  每个请求有自己的输入缓冲input_buffer、输出缓冲output_buffer。

总结一下evhttp:
  1. 一个evhttp使用一个链表存放多个evhttp_connection,每个evhttp_connection使用链表存放多个evhttp_request。
  2. 每个evhttp_connection包含一个bufferevent,每个evhttp_request包含两个evbuffer,用于输入输出缓冲。

说了半天,好像没看见同步机制,可见evhttp不适合多线程。

参考资料:

libevent源码浅析: http库














libevent(九)evhttp的更多相关文章

  1. libevent(十三)evhttp事件处理流程

    在libevent(六)http server中,作为一个单线程http server,不仅要监听每个连接的到来,还要监听每个连接上的I/O事件. 查看源码可知,在evhttp_bind_socket ...

  2. libevent(九)bufferevent

    bufferevent,带buffer的event struct bufferevent { struct event_base *ev_base; const struct bufferevent_ ...

  3. 编译libevent源代码(Windows)

    学习笔记,只是记录本次成功用libevent源代码进行编译.环境为MinGW+VS2008+Msys. 0.下载libevent库 http://libevent.org/ 下载stable稳定版的库 ...

  4. libevent(十)bufferevent 2

    接上文libevent(九)bufferevent 上文主要讲了bufferevent如何监听读事件,那么bufferevent如何监听写事件呢? 对于一个fd,只要它的写缓冲区没有满,就会触发写事件 ...

  5. Thrift 基础(C++ rpc )

    一.thrift简介 thrift是Facebook开源的一套rpc框架,目前被许多公司使用 我理解的特点 使用IDL语言生成多语言的实现代码,程序员只需要实现自己的业务逻辑 支持序列化和反序列化操作 ...

  6. libevhtp初探

    libevent的evhttp不适合多线程,libevhtp重新设计了libevent的http API,采用了和memcached类似的多线程模型. worker线程的管道读事件的回调函数为htp_ ...

  7. libevent源码深度剖析九

    libevent源码深度剖析九 ——集成定时器事件 张亮 现在再来详细分析libevent中I/O事件和Timer事件的集成,与Signal相比,Timer事件的集成会直观和简单很多.Libevent ...

  8. Libevent::evhttp服务器

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

  9. Libevent::evhttp服务器下载

    void http_handler_Get_Download(struct evhttp_request *req, void *arg) { if (req == NULL) { return; } ...

随机推荐

  1. SQL基础系列(3)-变量、函数、存储过程等

    1.    变量 定义变量 DECLARE @a INT 赋值 PRINT @a ) --select 赋值 SELECT @name='zcx' PRINT @name SELECT @name=F ...

  2. slice使用了解

    切片 什么是slice slice的创建使用 slice使用的一点规范 slice和数组的区别 slice的append是如何发生的 复制Slice和Map注意事项 什么是slice Go中的切片,是 ...

  3. Wpf之HandyControls与MaterialDesign混用之DataGrid

    首先在App.Xaml引入相关资源 <Application.Resources> <ResourceDictionary> <ResourceDictionary.Me ...

  4. 如何教零基础的人认识Python

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 编程派 PS:如有需要Python学习资料的小伙伴可以加点击下方链接 ...

  5. day18作业

    作业: # 1.编写课上讲解的有参装饰器准备明天默写 def auth(file_type): def outer(func): def inter(*args,**kwargs): if file_ ...

  6. 详解 Paths类 与 Files类

    在本篇博文中,本人主要讲解NIO 的两个核心点 -- 缓冲区(Buffer) 和 通道 (Channel)之一的 缓冲区(Buffer), 有关NIO流的其他知识点请观看本人博文<详解 NIO流 ...

  7. eclipse添加方法注释

    打开注释模板编辑窗口:Window ->Preferences->java -> Code Style -> Code Template->Comments type 设 ...

  8. HTTP Request和Response

    一.Servlet 1:实现Servlet接口 servlet生命周期: init方法:tomcat启动时 调用此方法 service方法:访问servlet时默认执行此方法 destroy方法:to ...

  9. 最简单的懒人springcloud之Eureka(服务注册与发现)

    本文开发软件是STS,是eclipse为springboot项目而生的一个软件,用这个软件开发spring的项目版本都会自己对应的,话不多说直接上代码 springboot版本2.1.8.RELEAS ...

  10. MySQL为某字段加前缀、后缀

    在开发过程中,可能会遇到加前缀或者后缀的情况.比如为视频添加路径时,如果手动加起来肯定慢,而且比较不符合程序员的特点,我们就应该能让程序跑就不会手动加. 使用UPDATE sql 语句:update ...