我使用的版本是libevent-2.0.21-stable。高级的应用还是得看官网文档 http://www.wangafu.net/~nickm/libevent-2.0/doxygen/html/
在目录下
./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.c log.c evutil.c evutil_rand.c strlcpy.c $(SYS_SRC) EXTRA_SRC = event_tagging.c http.c evdns.c evrpc.c libevent_pthreads_la_SOURCES = evthread_pthread.c libevent_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个的集合。
可以用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.lib 2015/02/26 10:40 789,110 libevent.lib 2015/02/26 10:40 453,366 libevent_core.lib
3个静态库文件。
不过一般会习惯做成VS工程。所以新建一个VS静态库工程,对着Makefile.nmake的内容添加源文件、引用目录、预编译命令就行了。vcproj的部分内容如下:
windows平台在链接时需要加入ws2_32.lib和wsock32.lib
若是能看懂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 := libevent LOCAL_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.c LOCAL_C_INCLUDES := \ $(LOCAL_PATH) \ $(LOCAL_PATH)/include \ $(LOCAL_PATH)/compat LOCAL_CFLAGS := -DHAVE_CONFIG_H include $(BUILD_SHARED_LIBRARY)
注意最后一行在集成到app时应该把BUILD_SHARED_LIBRARY应该替换成BUILD_STATIC_LIBRARY,这里仅为了编译。
libevent的核心作用是实现消息循环、消息队列管理与回调,可用来监听文件属性变化、超时、锁状态变化,其中超时可以用作Timer。
额外的功能是作为HTTP的server或client。
#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。
C++的封装。只是示例,HttpRequest和HttpResponse就不贴代码了。
// HttpClientTransaction.h
class 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#include "http_request.h" #include "mutable_http_response.h" void RequestCallback(struct evhttp_request* req, void *arg) { HttpClientTransaction* transaction = static_cast (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; }
比较简单,纯看代码能懂,就不解释了。
struct TimerCallbackArgument {
struct event* ev_event;
missile::Task* task;
};
void TimerCallback(evutil_socket_t fd, short what, void* arg) {
TimerCallbackArgument* ea = static_cast(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);
}
转载请注明出处:
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/30094666/viewspace-1474114/ ,如需转载,请注明出处,否则将追究法律责任。