llibevent2笔记(linux、windows、android的编译和HTTP client应用)

来源:互联网 发布:衣柜画图软件 编辑:程序博客网 时间:2024/06/07 17:30

0. 前言

我使用的版本是libevent-2.0.21-stable。高级的应用还是得看官网文档 http://www.wangafu.net/~nickm/libevent-2.0/doxygen/html/

1. 编译

1.1 Linux版编译

在目录下

./configure && make

即可在./.lib/下得到5个.a静态库。

不确定是否在此之前我已安装好各种依赖库所以没遇到任何障碍

liuhx@uc ~/Downloads/libevent-2.0.21-stable/.libs $ ll *.a-rw-r--r-- 1 liuhx liuhx 2309114 Feb 17 13:38 libevent.a-rw-r--r-- 1 liuhx liuhx 1431730 Feb 17 13:38 libevent_core.a-rw-r--r-- 1 liuhx liuhx  877456 Feb 17 13:38 libevent_extra.a-rw-r--r-- 1 liuhx liuhx  195868 Feb 17 13:38 libevent_openssl.a-rw-r--r-- 1 liuhx liuhx   21998 Feb 17 13:38 libevent_pthreads.a

查看Makefile文件的内容,可得知4个静态库对应的源文件:

CORE_SRC = event.c evthread.c buffer.c \  bufferevent.c bufferevent_sock.c bufferevent_filter.c \  bufferevent_pair.c listener.c bufferevent_ratelim.c \  evmap.clog.c evutil.c evutil_rand.c strlcpy.c $(SYS_SRC)EXTRA_SRC = event_tagging.c http.c evdns.c evrpc.clibevent_pthreads_la_SOURCES = evthread_pthread.clibevent_openssl_la_SOURCES = bufferevent_openssl.c

即libevent_core.a里是核心功能,其中$(SYS_SRC)在各个平台会不同,linux下是select.c、poll.c、 epoll.c、signal.c等,windows下是win32select.c evthread_win32.c等,不一一列举了。libevent_extra.a里包含http、dns等功能。另外两个libevent_*.a 就见名知意了。而libevent.a是其它4个的集合。

1.2 Windows版编译

可以用VS的Command Prompt(开始菜单->Visual Studio 2013->Visual Studio Tools->VS2013 x64 Native Tools Command Prompt,VS和CPU版本应对应到你所用的)在libevent目录下

nmake Makefile.nmake

就能得到

2015/02/26  10:40           336,040 libevent_extras.lib2015/02/26  10:40           789,110 libevent.lib2015/02/26  10:40           453,366 libevent_core.lib

3个静态库文件。

不过一般会习惯做成VS工程。所以新建一个VS静态库工程,对着Makefile.nmake的内容添加源文件、引用目录、预编译命令就行了。vcproj的部分内容如下:

<ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\buffer.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\bufferevent.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\bufferevent_async.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\bufferevent_filter.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\bufferevent_pair.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\bufferevent_ratelim.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\bufferevent_sock.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\buffer_iocp.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\evdns.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\event.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\event_iocp.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\event_tagging.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\evmap.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\evrpc.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\evthread.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\evthread_win32.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\evutil.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\evutil_rand.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\http.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\listener.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\log.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\signal.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\strlcpy.c" /><ClCompile Include="..\..\..\third_party\libevent-2.0.21-stable\win32select.c" />

windows平台在链接时需要加入ws2_32.lib和wsock32.lib

1.3 Android版编译

若是能看懂linux和windows的Makefile,那是很容易写好Android.mk的。但在此之前需要生成好android版的config.h和event-config.h。

目录下运行(ndk版本随意,请替换成对应的路径):

SYSROOT=~/Applications/android-ndk-r8e/platforms/android-8/arch-arm./configure --host=arm-linux-androideabi CC=~/Applications/android-ndk-r8e/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc CFLAGS=--sysroot=$SYSROOT

这样就会生成好config.h了。然后再

make

过程中会调用sed修改好event-config.h。顺利的话会生成四个.a

liuhx@uc ~/Downloads/libevent-2.0.21-stable/.libs $ ll *.a-rw-r--r-- 1 liuhx liuhx 455082 Feb 26 14:59 libevent.a-rw-r--r-- 1 liuhx liuhx 267398 Feb 26 14:59 libevent_core.a-rw-r--r-- 1 liuhx liuhx 187756 Feb 26 14:59 libevent_extra.a-rw-r--r-- 1 liuhx liuhx   4014 Feb 26 14:59 libevent_pthreads.a

因为没有编译OpenSSL,所以不会有libevent_openssl.a。

前面的过程会弄好config.h和event-config.h,其中event-config.h是对应android版本的配置,是必须 的,不然编不过,所以无法一上来就用Android.mk。过了make这一步才行,也就是要保留修改过的event-config.h来使用下面的 Android.mk

LOCAL_PATH := $(call my-dir)/..include $(CLEAR_VARS)LOCAL_MODULE := libeventLOCAL_SRC_FILES := \  event.c \  evutil.c \  epoll.c \  log.c \  poll.c \  select.c \  signal.c \  http.c \  buffer.c \  evthread.c \  evmap.c \  bufferevent.c \  listener.c \  evutil_rand.c \  bufferevent_sock.c \  bufferevent_filter.c \  bufferevent_pair.c \  strlcpy.c \  event_tagging.c \  evrpc.c \  bufferevent_ratelim.c \  evdns.c \  evthread_pthread.cLOCAL_C_INCLUDES := \  $(LOCAL_PATH) \  $(LOCAL_PATH)/include \  $(LOCAL_PATH)/compatLOCAL_CFLAGS := -DHAVE_CONFIG_Hinclude $(BUILD_SHARED_LIBRARY)

注意最后一行在集成到app时应该把BUILD_SHARED_LIBRARY应该替换成BUILD_STATIC_LIBRARY,这里仅为了编译。

2. 功能总结

libevent的核心作用是实现消息循环、消息队列管理与回调,可用来监听文件属性变化、超时、锁状态变化,其中超时可以用作Timer。

额外的功能是作为HTTP的server或client。

3. 使用

3.1 初始化

#include "event2/event.h"struct event_base* g_main_event_base = 0;struct event* g_time_limit_event = 0;void TimeLimitCallback(evutil_socket_t fd, short what, void* arg) {  event_del(g_time_limit_event);}int main(int argc, char* argv[]){#ifdef _WIN32  WSADATA WSAData;  WSAStartup(0x201, &WSAData);#endif  g_main_event_base = event_base_new();  g_time_limit_event = evtimer_new(g_main_event_base, &TimeLimitCallback, NULL);  struct timeval tv = {5 * 60, 0 };// 5 mins  evtimer_add(g_time_limit_event, &tv);  event_base_dispatch(g_main_event_base);  event_base_free(g_main_event_base);#ifdef _WIN32  WSACleanup();#endif  return 0;}

Windows平台需要额外地初始化网络库。

以上是相当于创建一个5分钟后触发的timer。event_base_dispatch会在所有event结束时才return。

3.2 HTTP client的实现

C++的封装。只是示例,HttpRequest和HttpResponse就不贴代码了。

// HttpClientTransaction.hclass HttpRequest;class HttpResponse;class HttpClientTransaction {public:  HttpClientTransaction(struct event_base* base);  ~HttpClientTransaction();  // Prioritization used in various parts of the networking code such  // as connection prioritization and resource loading prioritization.  enum Priority {    kIdle = 0,    kMinimumPriority = kIdle,    kLowest,    kDefaultPriority = kLowest,    kLow,    kMedium,    kHighest,    kMaximumPriority = kHighest  };  class Delegate {  public:    virtual ~Delegate() {}    virtual void OnResponseReceived(HttpClientTransaction* transaction,      HttpResponse* response) = 0;    virtual void OnBeforeRedirect(HttpClientTransaction* transaction,      const char* new_location) {}    virtual void OnDataReceived(HttpClientTransaction* transaction,      const char* data, size_t length) = 0;    virtual void OnFinished(HttpClientTransaction* transaction) = 0;    virtual void OnError(HttpClientTransaction* transaction, int error_code) = 0;  };  virtual void Start(int* out_error_code);  virtual void Cancel();  virtual HttpRequest* request() { return http_request_; }  virtual void set_request(HttpRequest* request) {    http_request_ = request;  }  virtual Delegate* delegate() { return delegate_; }  // implementation MUST NOT delete delegate  virtual void set_delegate(Delegate* delegate) { delegate_ = delegate; }  virtual Priority priority() { return priority_; }  virtual void set_priority(Priority priority) { priority_ = priority; }  void OnEvRequestCallback(evhttp_request* req);private:  struct event_base* base_;  HttpRequest* http_request_;  Delegate* delegate_;  Priority priority_;  struct evhttp_connection* ev_connection_;  struct evhttp_request* ev_request_;};

-------------------------------------------------------------------

// HttpClientTransaction.cpp#include "HttpClientTransaction.h"#include "event2/http.h"#include "event2/buffer.h"#include "event2/keyvalq_struct.h"#include <string>#include "http_request.h"#include "mutable_http_response.h"void RequestCallback(struct evhttp_request* req, void *arg) {  HttpClientTransaction* transaction = static_cast<HttpClientTransaction*>(arg);  transaction->OnEvRequestCallback(req);}HttpClientTransaction::HttpClientTransaction(struct event_base* base)  : base_(base),    http_request_(NULL),    delegate_(NULL),    priority_(kDefaultPriority) {}HttpClientTransaction::~HttpClientTransaction() {  Cancel();}void HttpClientTransaction::Start(int* out_error_code) {  if (!delegate_) {    *out_error_code = 1;    return;  }  if (!http_request_) {    *out_error_code = 4;    return;  }  const char* url = http_request_->url();  if (!url) {    *out_error_code = 11;    return;  }  struct evhttp_uri *uri = evhttp_uri_parse(url);  if (!uri) {    *out_error_code = 12;    return;  }  const char* host = evhttp_uri_get_host(uri);  if (!host) {    evhttp_uri_free(uri);    *out_error_code = 13;    return;  }  int port = evhttp_uri_get_port(uri);  if (port == -1)    port = 80;  const char* method = http_request_->method();  if (!method) {    evhttp_uri_free(uri);    *out_error_code = 14;    return;  }  evhttp_cmd_type cmd_type;  if (strcmp(method, "GET") == 0)    cmd_type = EVHTTP_REQ_GET;  else if (strcmp(method, "POST") == 0)    cmd_type = EVHTTP_REQ_POST;  else {    evhttp_uri_free(uri);    *out_error_code = 15;    return;  }  ev_connection_ = evhttp_connection_base_new(base_, NULL, host, port);  if (!ev_connection_) {    evhttp_uri_free(uri);    *out_error_code = 2;    return;  }  ev_request_ = evhttp_request_new(&RequestCallback, this);  void* iter = NULL;  const char* name = NULL;  const char* value = NULL;  struct evkeyvalq *headers = evhttp_request_get_output_headers(ev_request_);  while (http_request_->EnumerateHeaderLines(&iter, &name, &value)) {    evhttp_add_header(headers, name, value);  }  value = http_request_->GetHeader("host");  if (!value) {    evhttp_add_header(headers, "host", host);  }  const char* body = NULL;  size_t length = 0;  if (http_request_->body(&body, &length)) {    struct evbuffer *buffer = evhttp_request_get_output_buffer(ev_request_);    evbuffer_add(buffer, body, length);  }  int rv = evhttp_make_request(ev_connection_, ev_request_,    cmd_type, evhttp_uri_get_path(uri));  evhttp_uri_free(uri);  if (rv == -1) {    ev_request_ = NULL;    evhttp_connection_free(ev_connection_);    ev_connection_ = NULL;    *out_error_code = 3;    return;  }  *out_error_code = 0;  evhttp_connection_set_timeout(m_conn, http_request_->timeoutInterval());}void HttpClientTransaction::Cancel() {  if (ev_request_) {    evhttp_cancel_request(ev_request_);    ev_request_ = NULL;  }  if (ev_connection_) {    evhttp_connection_free(ev_connection_);    ev_connection_ = NULL;  }}void HttpClientTransaction::OnEvRequestCallback(evhttp_request* req) {  ev_request_ = NULL;  if (req == NULL) {    delegate_->OnError(this, 0xdead);  }  else {    MutableHttpResponse* response =      MutableHttpResponse::Create();    const char* url = http_request_->url();    response->set_url(url);    response->set_status_code(evhttp_request_get_response_code(req));    struct evkeyvalq* headers = evhttp_request_get_input_headers(req);    for (struct evkeyval* header = headers->tqh_first; header;      header = header->next.tqe_next) {      response->AddHeader(header->key, header->value);    }    delegate_->OnResponseReceived(this, response);    delete response;    response = NULL;    struct evbuffer *buf = evhttp_request_get_input_buffer(req);    while (evbuffer_get_length(buf)) {      int n;      char cbuf[128];      n = evbuffer_remove(buf, cbuf, sizeof(buf)-1);      if (n > 0)        delegate_->OnDataReceived(this, cbuf, n);    }    delegate_->OnFinished(this);  }  evhttp_connection_free(ev_connection_);  ev_connection_ = NULL;}

3.3 Timer的实现

比较简单,纯看代码能懂,就不解释了。

struct TimerCallbackArgument {  struct event* ev_event;  missile::Task* task;};void TimerCallback(evutil_socket_t fd, short what, void* arg) {  TimerCallbackArgument* ea = static_cast<TimerCallbackArgument*>(arg);  ea->task->Run();  event_del(ea->ev_event);  delete ea;}void PostDelayedTaskOnCurrentThread(Task* task,    unsigned delay_ms) {  TimerCallbackArgument* tca = new TimerCallbackArgument;  tca->task = task;  event* timer = evtimer_new(event_base_, &TimerCallback, tca);  tca->ev_event = timer;  struct timeval tv = {delay_ms / 1000000, delay_ms % 1000 * 1000};  evtimer_add(timer, &tv);}

转载请注明出处:

    • 本文来自:Linux教程网
0 0
原创粉丝点击