libevent evhttp学习——http客户端
基本环境
使用版本为libevent-2.1.5,目前为beta版,其中evhttp和旧版区别在于新增了如下接口
// 设置回调函数,在包头读取完成后回调
void evhttp_request_set_header_cb (struct evhttp_request *, int(*cb)(struct evhttp_request *, void *))// 设置回调函数,在body有数据返回后回调
void evhttp_request_set_chunked_cb (struct evhttp_request *, void(*cb)(struct evhttp_request *, void *))
- 1
- 2
- 3
- 4
- 5
这样的好处是可以在合适的时机回调我们注册的回调函数,比如下载1G的文件,在之前的版本只有下载完成后才会回调,现在每下载一部分数据就会回调一次,让上层应用更加灵活,尤其在http代理时,可以做到边下载边回复
2.1.5版本的完整接口文档详见http://www.wangafu.net/~nickm/libevent-2.1/doxygen/html/http_8h.html
请求流程
http客户端使用到的接口函数及请求流程如下
初始化event_base和evdns_base
struct event_base *event_base_new(void); struct evdns_base * evdns_base_new(struct event_base *event_base, int initialize_nameservers);
- 1
- 2
创建evhttp_request对象,并设置回调函数,这里的回调函数是和数据接收相关的
struct evhttp_request *evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg); void evhttp_request_set_header_cb(struct evhttp_request *, int (*cb)(struct evhttp_request *, void *)); void evhttp_request_set_chunked_cb(struct evhttp_request *, void (*cb)(struct evhttp_request *, void *)); void evhttp_request_set_error_cb(struct evhttp_request *, void (*)(enum evhttp_request_error, void *));
- 1
- 2
- 3
- 4
创建evhttp_connection对象,并设置回调函数,这里的回调函数是和连接状态相关的
struct evhttp_connection *evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase, const char *address, unsigned short port); void evhttp_connection_set_closecb(struct evhttp_connection *evcon,void (*)(struct evhttp_connection *, void *), void *);
- 1
- 2
- 3
- 4
有选择的向evhttp_request添加包头字段
int evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *value);
- 1
发送请求
int evhttp_make_request(struct evhttp_connection *evcon,struct evhttp_request *req,enum evhttp_cmd_type type, const char *uri);
- 1
- 2
- 3
派发事件
int event_base_dispatch(struct event_base *);
完整代码
#include "event2/http.h"
#include "event2/http_struct.h"
#include "event2/event.h"
#include "event2/buffer.h"
#include "event2/dns.h"
#include "event2/thread.h"#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/queue.h>
#include <event.h>void RemoteReadCallback(struct evhttp_request* remote_rsp, void* arg)
{event_base_loopexit((struct event_base*)arg, NULL);
} int ReadHeaderDoneCallback(struct evhttp_request* remote_rsp, void* arg)
{fprintf(stderr, "< HTTP/1.1 %d %s\n", evhttp_request_get_response_code(remote_rsp), evhttp_request_get_response_code_line(remote_rsp));struct evkeyvalq* headers = evhttp_request_get_input_headers(remote_rsp);struct evkeyval* header;TAILQ_FOREACH(header, headers, next){fprintf(stderr, "< %s: %s\n", header->key, header->value);}fprintf(stderr, "< \n");return 0;
}void ReadChunkCallback(struct evhttp_request* remote_rsp, void* arg)
{char buf[4096];struct evbuffer* evbuf = evhttp_request_get_input_buffer(remote_rsp);int n = 0;while ((n = evbuffer_remove(evbuf, buf, 4096)) > 0){fwrite(buf, n, 1, stdout);}
}void RemoteRequestErrorCallback(enum evhttp_request_error error, void* arg)
{fprintf(stderr, "request failed\n");event_base_loopexit((struct event_base*)arg, NULL);
}void RemoteConnectionCloseCallback(struct evhttp_connection* connection, void* arg)
{fprintf(stderr, "remote connection closed\n");event_base_loopexit((struct event_base*)arg, NULL);
}int main(int argc, char** argv)
{if (argc != 2){printf("usage:%s url", argv[1]);return 1;}char* url = argv[1];struct evhttp_uri* uri = evhttp_uri_parse(url);if (!uri){fprintf(stderr, "parse url failed!\n");return 1;}struct event_base* base = event_base_new();if (!base){fprintf(stderr, "create event base failed!\n");return 1;}struct evdns_base* dnsbase = evdns_base_new(base, 1);if (!dnsbase){fprintf(stderr, "create dns base failed!\n");}assert(dnsbase);struct evhttp_request* request = evhttp_request_new(RemoteReadCallback, base);evhttp_request_set_header_cb(request, ReadHeaderDoneCallback);evhttp_request_set_chunked_cb(request, ReadChunkCallback);evhttp_request_set_error_cb(request, RemoteRequestErrorCallback);const char* host = evhttp_uri_get_host(uri);if (!host){fprintf(stderr, "parse host failed!\n");return 1;}int port = evhttp_uri_get_port(uri);if (port < 0) port = 80;const char* request_url = url;const char* path = evhttp_uri_get_path(uri);if (path == NULL || strlen(path) == 0){request_url = "/";}printf("url:%s host:%s port:%d path:%s request_url:%s\n", url, host, port, path, request_url);struct evhttp_connection* connection = evhttp_connection_base_new(base, dnsbase, host, port);if (!connection){fprintf(stderr, "create evhttp connection failed!\n");return 1;}evhttp_connection_set_closecb(connection, RemoteConnectionCloseCallback, base);evhttp_add_header(evhttp_request_get_output_headers(request), "Host", host);evhttp_make_request(connection, request, EVHTTP_REQ_GET, request_url);event_base_dispatch(base);return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
编译
g++ http_client.cpp -I/opt/local/libevent-2.1.5/include -L/opt/local/libevent-2.1.5/lib -levent -g -o http_client
运行示例,这里只打印了包头字段
$ ./http_client http://www.qq.com >/dev/null
< HTTP/1.1 200 OK
< Server: squid/3.4.3
< Content-Type: text/html; charset=GB2312
< Cache-Control: max-age=60
< Expires: Fri, 05 Aug 2016 08:48:31 GMT
< Date: Fri, 05 Aug 2016 08:47:31 GMT
< Transfer-Encoding: chunked
< Connection: keep-alive
< Connection: Transfer-Encoding
<
libevent evhttp学习——http客户端相关推荐
- libevent evhttp学习——http服务端
http服务端相对客户端要简单很多,我们仍旧使用libevent-2.1.5版本,服务端接口和2.0版本没有区别 基本流程 http服务端使用到的借口函数及流程如下 创建event_base和evht ...
- 【libevent】libevent库学习总结(一)——基础
libevent库学习总结(一)--基础 一.基础 1.1. 介绍 Libevent是一个用于开发可伸缩网络服务器的事件通知库.Libevent API提供了一种机制来执行回调函数,当某个特定事件发生 ...
- WPF学习开发客户端软件-任务助手(下 2015年2月4日代码更新)
时光如梭,距离第一次写的 WPF学习开发客户端软件-任务助手(已上传源码) 已有三个多月,期间我断断续续地对该项目做了优化.完善等等工作,现在重新向大家介绍一下,希望各位可以使用,本软件以实用性为主 ...
- webService学习4:客户端调用服务端的代码
1 服务器端sayHello变化了一点,代码如下 @WebService public class HelloWSImpl implements HelloWS {public String sayH ...
- 学习云客户端安装流程
学习云客户端安装流程 通过网盘链接下载好文件后,通过接下来的三部来完成安装操作 安装客户端 解压镜像文件 配置BIOS 虚拟化与安全启动 下面是两个配置的链接,可以先配置起来,也可以安装完再配置 wi ...
- 【国产数据库】GBase学习⑤ - gsql 客户端连接工具
[国产数据库]GBase学习⑤ - gsql 客户端连接工具 gsql介绍 gsql使用方式 DBeaver客户端工具配置 gsql介绍 GBase 8c 客户端工具是gsql.类似于MySQL的my ...
- 学习OCS客户端定制
一步一步学习OCS2007(一)--如何定制在线状态?(转自:http://www.cnblogs.com/invinboy ) OCS 2007(即Microsoft Office Communic ...
- openfire学习4---android客户端聊天开发之聊天功能开发
前面我们已经把服务器搭建完成,并且在客户端实现了登录了. 和我们使用的QQ一样,想一想,登录成功之后呢?肯定是要有一个好友列表,通过这个列表,我们可以选择我们需要聊天的好友. 这里我们先研究下 xmp ...
- Android HIDL 介绍学习之客户端调用
应上一篇文章Android HIDL 介绍学习_Super Jang的博客-CSDN博客_安卓hidl读者的要求,本文更新客户端调用方法. hidl的客户端调用相比服务端的实现要简单很多,本次我们通过 ...
最新文章
- 使用wsimport生成本地调用代码
- 循环语句——7月23日
- 计算机网络与通信pdf谢希仁_考研刷题资料谢希仁《计算机网络》(第7版)配套题库【考研真题精选(部分视频讲解)+章节题库】...
- java 根据当前时间获得一周日期
- 锁相放大器sr830_各位谁会用Stanford SR830啊,我都快被这个锁相放大器折腾死了!!!!-北京搜狐焦点...
- python c4.5完整代码_python实现c4.5/Id3自我练习
- python求解二次规划_Python二次规划和线性规划使用实例
- python-zip方法
- 比特币技术公司创始人:ICO是一场被骗子玩弄的网络泡沫
- JQuery Ajax 解析
- Redis在游戏服务器中的应用
- python基础-菜鸟世界 -python基础---set
- 根据自身工作经验总结的一个工作问题解决思路
- [20170516]nvl与非NULL约束.txt
- redis zset底层数据结构
- ps怎么撤销参考线_Photoshop120条新手必备技巧
- WiFi通信模块框图
- Learn Git Branching 学习笔记(关于origin和它的周边——Git远程仓库高级操作篇)
- Intel opreation mode
- 英特尔Skylake处理器全面入驻Google Compute Engine
热门文章
- adjacent angle_GRE/GMAT 数学之平面几何
- STM32----摸石头过河系列(五)
- C4D插件:Springy for Mac 动​​画对象添加重叠动作插件
- 1.5编程基础之循环控制 34 求阶乘的和
- 正则表达式加参数匹配
- flutter引入高德地图_Flutter笔记-调用原生IOS高德地图sdk
- Qt文档阅读笔记-RadioButton的基本使用
- HTTP中CORS跨域请求的实现(C++|Qt框架实现)
- Java基础入门笔记-使用变量并打印
- 计算特征矩阵及哈希值(含OpenCV代码)