libevet异步发送消息的原理
说明
代码未验证,只设计其逻辑, 工作中是成功的,不能给出.
- 类似场景:
单线程的网络库
csharp的UI异步线程
Andorid的UI异步通知
- 凡是单线程业务通知,都有其自定义通知的过程, 然后在自定义通知逻辑中实现遍历具体的单线程任务中模块(IO, UI布局等), 得到后进行操作.
逻辑
通过参考libevent源码,采用socketpair
static evutil_socket_t pair[2]; //[0]发送 [1]接收
struct evhttp* http = NULL;
struct event* evpair = NULL; //单独的io socket
//http的构建过程忽略
if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
return (1);
evutil_make_socket_nonblocking(pair[0]);
evutil_make_socket_nonblocking(pair[1]);
evpair = event_new(base, pair[1], EV_READ | EV_PERSIST, _pair_callbk, http);
if (event_add(evpair, NULL))
goto err;
static void _pair_callbk(evutil_socket_t fd, short event, void* arg)
{
char buf[256] = { 0 };
int len;
struct evhttp* http = (struct evhttp*)arg;
len = recv(fd, buf, sizeof(buf), 0);
//异步发送消息(这里只是一个测试,如果send_reply有释放req操作就会出错)
TAILQ_FOREACH(evcon, &http->connections, next)
{
TAILQ_FOREACH(req, &evcon->requests, next)
{
//在这里进行异步
evhttp_send_reply(req, 200, "OK", buff);
}
}
}
进行c++11多线程处理回复
std::vector<std::function<void(struct evhttp_request*)>> funcs;
std::thread td([]{
sleep(8); //8秒的耗时操作
//这里需要给指定的req发送消息
std::string msg="hello";
std::function<void(struct evhttp_request*)> response=[msg](struct evhttp_request* req){
struct evbuffer *buff=evbuffer_new();
evbuffer_add(evb, msg.c_str(), msg.size());
evhttp_send_reply(req, 200, "OK", buff);
evbuffer_free(buff);
//从funcs中删除自己, 可以自己封装类来处理,有点像csharp的ui异步线程通知类
};
funcs.push_back(response);
send(pair[0], "n", 1, 0); //让event进入_pair_callbk
});
//修改上面的evhttp_send_reply
for(auto &fun:funcs){
fun(req);
}
libevent-http模块的一小点说明
如果是文件上传: libevent-http.c 会读取Content-length的长度,到req->inputbuf中,只有数据达到这个长度后, 才会进入done中的 gencb() 功能,即自定义回调.
回调处理
在 gencb中对req增加回调函数,在其回调中对req关联的任务线程进行释放
//链接断开
static void on_evcnclose_cb(struct evhttp_connection* evcn, void* arg)
{
LOGD("ws", "evcn close cb\n");
struct evhttp_request* req = (struct evhttp_request*)arg;
}
//请求完成
static void req_on_complete_cb(struct evhttp_request* req, void* arg)
{
LOGD("ws", "req_on_complete_cb\n");
}
//
void http_gencb(struct evhttp_request *request, void* arg)
{
evhttp_request_set_on_complete_cb(req, req_on_complete_cb, NULL);
evhttp_connection_set_closecb(evhttp_request_get_connection(req), on_evcnclose_cb, req);
}