libevent实现的HTTP Server

2023-05-16

在使用C语言编码时, 有时候需要实现一个HTTP接口, 我们可以选择使用libevent库来实现.
以下代码演示了使用libevent, 并同时支持多线程处理HTTP的请求.

头文件

引入的头文件:

#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <event2/http.h>
#include <event2/http_struct.h>
#include <event2/keyvalq_struct.h>

创建多线程监听

创建socket, 使用了APR库.

apr_socket_t* http_socket_create(apr_port_t port, apr_pool_t* pool)
{
	apr_status_t rv;
	apr_socket_t* socket = NULL;
	apr_sockaddr_t* addr;
	char msg[246];

	do
	{
		// 创建socket.
		rv = apr_socket_create(&socket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, pool);
		if (APR_SUCCESS != rv)
		{
			apr_strerror(rv, msg, sizeof(msg));
			dzlog_fatal("failed to create socket, port:%u, reason:%s", port, msg);
			break;
		}

		rv = apr_sockaddr_info_get(&addr, 0, APR_INET, port, 0, pool);
		if (APR_SUCCESS != rv)
		{
			apr_strerror(rv, msg, sizeof(msg));
			dzlog_fatal("apr_sockaddr_info_get failed, reason:%s", msg);
			break;
		}

		apr_socket_opt_set(socket, APR_SO_NONBLOCK, 1);
		apr_socket_opt_set(socket, APR_SO_LINGER, 1);
		apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1);

		// 绑定端口。
		rv = apr_socket_bind(socket, addr);
		if (APR_SUCCESS != rv)
		{
			apr_strerror(rv, msg, sizeof(msg));
			dzlog_fatal("failed to bind port %u", port);
			break;
		}

		return socket;
	} while (0);

	if (socket) apr_socket_close(socket);
	return NULL;
}

多线程监听:

	_server->http_socket = http_socket_create(_server->http_port, _server->pool);
	apr_socket_listen(_server->http_socket, 5);
	apr_os_sock_get(&fd, _server->http_socket);
	// 创建多个线程, 监听同一个socket.
	for (i = 0; i < _server->http_thread_number; i++)
	{
		struct event_base* base = event_base_new();
		struct evhttp* http = evhttp_new(base);

		_server->http_servers[i].base = base;
		_server->http_servers[i].http = http;

		evhttp_accept_socket(http, fd);
		// 设置入口函数(回调函数), 每个线程独立使用自身的MySQL句柄.
		evhttp_set_gencb(http, &http_server_handler, NULL);

		// 创建线程? 需要修改为多线程.
		apr_thread_create(&_server->http_servers[i].thread, NULL, &http_server_thread, base, _server->pool);
	}

线程函数:

static void* APR_THREAD_FUNC http_server_thread(apr_thread_t* thread, void* arg)
{
	struct event_base* base = (struct event_base*)arg;
	event_base_dispatch(base);
	return NULL;
}

HTTP请求入口函数:

static void http_server_handler(struct evhttp_request* req, void* arg)
{
	int code;
	const struct evhttp_uri* uri = evhttp_request_get_evhttp_uri(req);
	if (NULL == uri)
	{
		dzlog_error("http: evhttp_request_get_evhttp_uri null");
		evhttp_send_error(req, HTTP_BADREQUEST, NULL);
		return;
	}

	const char* url = evhttp_uri_get_path(uri);
	if (NULL == url)
	{
		dzlog_error("http: evhttp_uri_get_path fail");
		evhttp_send_error(req, HTTP_BADREQUEST, NULL);
		return;
	}
	
	struct evbuffer* evb = evbuffer_new();
	evbuffer_expand(evb, 4 * 1024);
	switch (evhttp_request_get_command(req))
	{
	case EVHTTP_REQ_POST:
		// 处理POST请求.
		{
			struct evbuffer* ib;
			const char* body;
			ib = evhttp_request_get_input_buffer(req);
			if (NULL != ib)
			{
				// 可能没有BODY
				evbuffer_add(ib, "\0", 1);
				body = (const char*)evbuffer_pullup(ib, -1);

				cJSON* root = cJSON_Parse(body);
				if (NULL == root)
				{
					dzlog_warn("HTTP: invalid JSON, URL=[%s], BODY=[%s]", url, body);
					code = HTTP_EXPECTATIONFAILED;
					mdf_set_errcode(evb, ERR_INVALID_JSON);
				}
				else
				{
					dzlog_debug("HTTP: Receive 'POST', URL='%s', BODY=%s", url, body);
					on_http_post(app, root, evb);
					cJSON_Delete(root);
				}
			}
			break;
		}
	case EVHTTP_REQ_GET:
		{
			struct evkeyvalq headers = { 0 };
			if (0 == evhttp_parse_query_str(evhttp_uri_get_query(evhttp_request_get_evhttp_uri(req)), &headers))
			{
				code = on_http_get(app, &headers, evb);
				evhttp_clear_headers(&headers);
			}
			break;
		}
		......
	}

	evhttp_send_reply(req, code, NULL, evb);
	evbuffer_free(evb);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

libevent实现的HTTP Server 的相关文章

  • 通过PHP从网站上传文件到Amazon EC2服务器

    我有一个网站 bedatify com 我想创建一个页面 人们可以在其中将图像上传到我的亚马逊 EC2 服务器 我检查了类似的问题 例如无法在 Amazon EC2 上上传文件 php https stackoverflow com que
  • 使用创建的 201 进行重定向

    有没有办法通过 201 答案重定向 RFC规定新创建的资源必须在Location标题 我确实指定了它 我假设浏览器会重定向 但事实并非如此 即使页面没有内容 我希望用户在 POST 操作之后重定向到新资源 因此我很想使用303 See Ot
  • 如何使用 Apache HttpClient 4 获取文件上传的进度条?

    我有以下用于使用 Apache 的 HTTP Client org apache http client 上传文件的代码 public static void main String args throws Exception String
  • 构建可扩展 Web 应用程序的书籍? (数据库性能/调优、网络、一般性能等)[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 从计算机科学专业毕业并作为一名从事 Web 应用程序的软件工程师进入 现实世界 后 我对如何正确扩展 W
  • 把自己限制在HTTP1.0有什么用吗?

    我负责构建一些工具来帮助最终用户测试为什么他们的浏览器可能无法与网站配合使用 我被告知它可能不起作用的原因之一是 需要 HTTP1 1 这一行 我浏览了大多数浏览器选项 只浏览了 IE 版本 6 及更高版本 even 9 允许您禁用 HTT
  • Node.js 中的 HTTPS 代理服务器

    我正在开发一个node js代理服务器应用程序 我希望它支持HTTP and HTTPS SSL 协议 作为服务器 我目前正在使用node http proxy https github com nodejitsu node http pr
  • WCF - 进行多次调用时随机客户端超时

    我有一个WPF客户端通过以下方式请求数据WCF服务托管于IIS 7 服务方法调用存储过程 SQL 2012 using EF检索一些数据 由于需要加载大量数据 因此客户端会多次调用服务方法 以 分解 数据加载并避免大量负载和超时 我们使用生
  • 内容长度标头与分块编码

    我正在尝试权衡设置的利弊Content LengthHTTP 标头与使用分块编码从我的服务器返回 可能 大文件的比较 使用持久连接需要其中之一来符合 HTTP 1 1 规范 我看到了的优点Content Length标头是 下载对话框可以显
  • Express.js在控制器中获取http方法

    我正在构建一个注册表单 本地护照作为身份验证 表单作为表单助手 因为注册只知道 GET 和 POST 我想在一个函数中完成整个处理 换句话说 我正在寻找类似的东西 exports register function req res if r
  • 对过期会话进行休息调用:HTTP 401 响应导致浏览器显示登录窗口

    我编写了一个 HTML 5 应用程序 它使用 AngularJS 并与在 Tomcat 上运行的 Java REST 后端进行交互 我使用 Spring Security 来处理登录和安全性 当用户进入网站时 他将被转发到登录页面 该页面创
  • 是否有用于通过 HTTP、HTTP 隧道发送二进制数据的 Java 库?

    我想通过 HTTP 以二进制格式发送相当大的数据块 也称为HTTP 隧道 http en wikipedia org wiki HTTP tunnel 我想通过 Java 将这种技术用于一些 Java Swing 应用程序 也可能是 And
  • 使用 Google OAuth2.0 时出现错误请求

    从 Salesforce 中使用 Google OAuth 时 我收到 400 错误请求 以下错误与无效的 grant type 有关 但如果您查看 使用刷新令牌 下的文档 您会发现它是正确的 https developers google
  • 数据包无序。得到:80 预期:0 node.js

    这是我的 非常简单 代码 var connection mysql createConnection infosDB connection connect connection query SELECT FROM action functi
  • 为什么使用HTTP协议时需要指定端口号?

    即使我们使用HTTP协议 为什么还需要用IP地址指定端口号 例如 http xyz 8080 这到底是什么意思 我们已经知道 在使用 HTTP 时 请求将在端口 80 上提供服务 那么为什么我们要显式指定端口呢 HTTP 的默认端口为 80
  • 服务器返回网页 404,但页面在浏览器中显示正常 - 为什么?

    一个奇怪的网页横亘在我面前 作为一名开发人员 我必须解开这个谜团 在任何浏览器中访问网页时 一切似乎都很正常 网页按预期显示 但是当查看控制台时 服务器实际上返回了 404 状态代码 那么浏览器为什么要渲染页面呢 查看正文显示返回了有效的
  • 通过 HTTPS 加载页面但请求不安全的 XMLHttpRequest 端点

    我有一个页面 上面有一些 D3 javascript 该页面位于 HTTPS 网站内 但证书是自签名的 当我加载页面时 我的 D3 可视化效果不显示 并且出现错误 混合内容 页面位于 https integration jsite com
  • 将 HttpApi 与 I/O 完成端口结合使用

    我刚刚偶然发现了微软的HTTP 服务器 API http msdn microsoft com en us library aa364510 28v vs 85 29 aspx 简介中写道 HTTP 服务器 API 使应用程序能够通过 HT
  • MPMoviePlayerController 播放 YouTube 视频

    如何在 iPhone 上的 MPMoviePlayerController 中播放 YouTube 视频 同时避免进入全屏模式 这个问题已经在这里提出 MPMoviePlayerController 正在播放 YouTube 视频吗 htt
  • 套接字:监听积压并接受

    listen sock backlog 在我看来 参数backlog限制连接数量 这是我的测试代码 server initialize the sockaddr of server server sin family AF INET ser
  • .net core 2.0代理请求总是导致http 407(需要代理身份验证)

    我正在尝试通过 net core 2 0 Web 应用程序中的 WebProxy 发出 HTTP 请求 我得到的代码在 net框架中运行良好 所以我知道 相信 这不是环境问题 我也尝试使用两者来发出请求HttpWebRequest and

随机推荐

  • github cli 创建远程仓库并推送到github

    以下操作基于macOS xff0c 其他系统安装请参阅官方文档cli cli GitHub s official command line tool 1 安装github cli brew span class token function
  • 阿里云生活物联网删除测试设备

    阿里云生活物联网平台 https living aliyun com 的测试设备 xff0c 在生活物联网平台页面是无法进行删除的 xff0c 生活物联网平台的设备列表只能显示量产设备 如果要删除测试设备 xff0c 必须在物联网平台 ht
  • STM32CubeMX学习教程之四:定时器中断

    完整源码下载 xff1a https github com simonliu009 STM32CubeMX TIM1 Interrupt 软件 xff1a STM32CubeMX V4 25 0 System Workbench V2 4
  • 算法——贝塞尔(Bézier)曲线拟合

    文章目录 1 基本概念 1 1 从熟悉的地方入手 1 2 贝塞尔曲线拟合原理 转载 2 公式和物理意义 2 0 阶数和伯恩斯坦多项式等 2 0 1 阶数 2 0 2 伯恩斯坦多项式 2 0 3 杨辉三角和二项式系数 2 1 一阶 次贝塞尔公
  • STM32CubeMX学习教程之五:PWM实现呼吸灯效果

    完整源码下载 xff1a https github com simonliu009 STM32CubeMX PWM Output 软件 xff1a STM32CubeMX V4 25 0 System Workbench V2 4 固件库版
  • STM32CubeMX学习教程之十:硬件I2C读写AT24C02

    完整源码下载 xff1a https github com simonliu009 STM32CubeMX hardware I2C AT24C02 网上有流传已久一种说法 xff0c 就是STM的I2C有bug xff0c 不好用 确实很
  • Visual Studio Code 的 includePath 全局设置

    这几天折腾使用Visual Studio Code 编写 ESP8266 non os 代码 xff0c 基本设置都没问题 xff0c 但是就是自动补全折腾很久没弄好 在折腾了一圈插件之后 xff08 包括Auto Import C 43
  • 使用.gitignore忽略文件或者文件夹及其失效解决方法

    git如果需要忽略某个文件夹 xff0c 可以在初始化之后 xff0c 在仓库根目录下创建一个 gitignore文件 xff0c 添加需要忽略的文件和文件夹即可 我们也不需要从头写 gitignore文件 xff0c GitHub已经为我
  • python源代码文件加密

    由于python设计的初衷是开源的 xff0c 因此py文件是可以直接看到源码的 但开发商业软件 xff0c 代码加密保护就比较重要了 python编译后程序 pyc文件是py文件经过编译后生成的二进制文件 xff0c 因此可以发布pyc文
  • gnu binutils

    The GNU Binutils are a collection of binary tools The main ones are ld the GNU linker as the GNU assembler But they also
  • android wakelock

    1 android休眠控制锁 powermanager acquir 获取控制锁 powermanager release 释放控制锁 2 在powerManagerService中 xff0c 有检测当前framework层中的wakel
  • 产品经理常用术语

    产品经理常用术语 长尾理论 网络时代兴起的一种新理论 xff0c 由于成本和效率的因素 xff0c 当商品储存流通展示的场地和渠道足够宽广 xff0c 商品生产成本急剧下降以至于个人都可以进行生产 xff0c 并且商品的销售成本急剧降低时
  • 传统CD车机面板操作说明

    转自http bbs hifidiy net thread 675597 1 1 html 一般CD车机带USB SD卡的面板操作说明 1 1 控制面板外观图 2 0 基本 共同 功能操作说明 2 1 开启和关闭电源 静音开关 按 钮为开启
  • 汽车总线系统通信协议

    天合汽车零部件 xff08 上海 xff09 有限公司 上海交通大学区域光纤通信网与新型光通信系统国家重点实验室 xff08 上网时间 xff1a 2006 11 xff09 摘要 xff1a 本文主要针对汽车电子控制系统和车载多媒体系统
  • 算法——连续性后处理(把26邻域连续的变成6邻域连续的)

    文章目录 1 概念 1 1 6邻域连续 1 2 18邻域连续 1 3 26邻域连续 1 4 总结 2 目标 3 严格一点的 3 1 原理描述 3 1 1 18邻域连续补充 3 1 2 26邻域连续补充 3 2 代码实现 C 4 宽松一点的
  • RedHat Linux下安装JDK1.7报错Permission denied

    在RedHat Linux5 中安装JDK1 7时 xff0c 当我解压jdk xff0c 并且配置好了环境变量 xff0c 测试的时候 xff0c 报以下错误 root 64 jingfeng01 java version Error d
  • 几种压缩算法的压缩和速度比较

    Quick Benchmark Gzip vs Bzip2 vs LZMA vs XZ vs LZ4 vs LZO EDIT Add zstd Contents hide 1 Selected archives2 Test conditio
  • DDR低功耗模式

    DDR规格 xff1a DDR工作状态图 xff1a DDR 刷新描述 xff1a 电特性 xff1a 工作模式简介 xff1a 1 1 自刷新模式 xff08 Self Refresh Mode xff09 DDR4 SDRAM中自刷新超
  • 嵌入式Linux的低功耗策略

    引 言 由于Linux系统具备嵌入式操作系统需要的很多特色 xff0c 如适应于多种CPU和多种硬件平台 性能稳定 可裁剪性很好 源码开放 研发和使用简单等 现在 xff0c 基于Linux应用的嵌入式设备日益增多 xff0c Linux正
  • libevent实现的HTTP Server

    在使用C语言编码时 有时候需要实现一个HTTP接口 我们可以选择使用libevent库来实现 以下代码演示了使用libevent 并同时支持多线程处理HTTP的请求 头文件 引入的头文件 span class token macro pro