服务器libevent bufferevent 初窥

1,最近在学习libevent,记录一下学习过程了,于是简单的一个服务器,回显而已

2,代码

#include <iostream>
#include <stdlib.h>
#include <event.h>
#include <sys/stat.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
using namespace std;

void read_callback(struct bufferevent *bev, void *ctx)
{
	struct evbuffer *input, *output;
	char *request_line;
	size_t len;
	/************************************************************************/
	/*struct evbuffer *bufferevent_get_input(struct bufferevent *bufev);
	  struct evbuffer *bufferevent_get_output(struct bufferevent *bufev);
	  they return the input and output buffers respectively.
	  For full information on all the operations you can perform on an evbuffer type                                                                     */
	/************************************************************************/
	input = bufferevent_get_input(bev);
	output = bufferevent_get_output(bev);

	size_t input_len = evbuffer_get_length(input);
	printf("input_len: %d\n", input_len);
	// 从evbuffer前面取出一行,用一个新分配的空字符结束的字符串返回这一行, EVBUFFER_EOL_CRLF表示行尾是一个可选的回车,后随一个换行符
	while (request_line = evbuffer_readln(input, &len, EVBUFFER_EOL_CRLF))
	{
		printf("Get one line date: %s\n", request_line);

		char *response = "Response ok! Hello Client!\r\n";
		evbuffer_add(output, response, strlen(response));//Adds data to an event buffer
		printf("server send: %s\n", response);
	}
	free(request_line);
}

void event_callback(struct bufferevent *bev, short events, void *ctx)
{
	if (events & BEV_EVENT_EOF)
	{
		/*eof occur*/
	}
	else if (events & BEV_EVENT_ERROR)
	{
		int err = EVUTIL_SOCKET_ERROR();
		printf("errno = %d on lister: %s\n", err, evutil_socket_error_to_string(err));
	}
	else if (events & BEV_EVENT_TIMEOUT)
	{
		/*timeout occur*/
	}
	/************************************************************************/
	/* This function frees a bufferevent. Bufferevents are internally reference-counted,
	so if the bufferevent has pending deferred callbacks when you free it,
	it won’t be deleted until the callbacks are done.                                                                     */
	/************************************************************************/
	bufferevent_free(bev);
}

void on_accept(evutil_socket_t sock, short event, void *arg)
{
	struct event_base *base =(struct event_base*) arg;
	/************************************************************************/
	/* The SOCKADDR_STORAGE structure stores socket address information.
	Since the SOCKADDR_STORAGE structure is sufficiently large to store address information for IPv4, IPv6, or other address families,
	its use promotes protocol-family and protocol-version independence and simplifies cross-platform development.
	Use the SOCKADDR_STORAGE structure in place of the sockaddr structure                                                                     */
	/************************************************************************/
	struct sockaddr_storage ss;
	socklen_t len = sizeof(ss);
	int fd = accept(sock, (struct sockaddr*)&ss, &len);
	if (fd < 0)
	{
		perror("error accpet");
	}
	else if (fd > FD_SETSIZE)
	{
		close(fd);
	}
	else
	{

		struct bufferevent *bev;

		/************************************************************************/
		/*   Make sure that the socket you provide to bufferevent_socket_new is in non-blocking mode.
			Libevent provides the convenience method evutil_make_socket_nonblocking for this                                                                   */
		/************************************************************************/

		evutil_make_socket_nonblocking(fd);

		/************************************************************************/
		/*   BEV_OPT_CLOSE_ON_FREE  When the bufferevent is freed, close the underlying transport.
		This will close an underlying socket, free an underlying bufferevent                                                                   */
		/************************************************************************/

		bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

		/************************************************************************/
		/* The bufferevent_setcb() function changes one or more of the callbacks of a bufferevent. The readcb, writecb, and eventcb functions are called (respectively)
		when enough data is read, when enough data is written, or when an event occurs. The first argument of each is the bufferevent that has had the event happen.
		typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
		void bufferevent_setcb(struct bufferevent *bufev,
		bufferevent_data_cb readcb, bufferevent_data_cb writecb,
		bufferevent_event_cb eventcb, void *cbarg);                                                                     */
		/************************************************************************/

		bufferevent_setcb(bev, read_callback, NULL, event_callback, NULL);

		/************************************************************************/
		/* You can enable or disable the events EV_READ, EV_WRITE, or EV_READ|EV_WRITE on a bufferevent.
		   When reading or writing is not enabled, the bufferevent will not try to read or write data                                                                     */
		/************************************************************************/
		bufferevent_enable(bev, EV_READ | EV_WRITE);
	}
}

int  init(void)
{
	int sock;

	struct event_base *base;

	struct event listen_ev;

	base = event_base_new();
	if (!base)
		return -1;

	struct addrinfo hints, *addr;
	int ret;
	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_flags = AI_PASSIVE;
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;

	ret = getaddrinfo(NULL, "8888", &hints, &addr);
	if (ret != 0) {
		printf("getaddrinfo error: %s\n", gai_strerror(ret));
		return -1;
	}

	while (addr != NULL)
	{
		sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
		if (sock < 0) {
			perror("open socket error");
			return -1;
		}

		evutil_make_socket_nonblocking(sock);
		evutil_make_listen_socket_reuseable(sock);
		ret = bind(sock, (struct sockaddr *)addr->ai_addr, addr->ai_addrlen);
		if (ret < 0)
		{
			perror("bind error");
			close(sock);
			addr = addr->ai_next;
			continue;
		}
		break;
	}
	if (listen(sock, 16) < 0)
	{
		perror("listen");
		return -1;
	}

	event_assign(&listen_ev, base, sock, EV_READ | EV_PERSIST, on_accept, (void*)base);

	event_add(&listen_ev, NULL);
	event_base_set(base, &listen_ev);
	event_base_dispatch(base);
	return 0;
}

int main(int argc, char **argv)
{
	init();
	return 0;
}
时间: 2024-08-29 01:05:18

服务器libevent bufferevent 初窥的相关文章

初窥netfilter/iptables

做这个东西太麻烦了,一不小心,就被自己关门外了. ---------------------------------------------- 一.前言 二.环境 三.语法解析 四.配置及测试 1.SNAT案例 2.DNAT案例 3.SSH案例 4.SSH深入案例(自定义规则) 5.web和ftp(自定义规则) 6.web和ftp(系统默认规则) 五.保存 ---------------------------------------------- 一.前言 iptables即Linux 内核集

Java发送邮件初窥

一.背景 最近朋友的公司有用到这个功能,之前对这一块也不是很熟悉,就和他一起解决出现的异常的同时,也初窥一下使用Apache Common Email组件进行邮件发送. 二.Java发送邮件的注意事项 1.不同的邮箱有不同的支持协议,比如有些只支持SSL协议,有些只支持TLS协议,还有些同时支持SSL和TLS协议. 2.支持不同协议的邮箱,在使用Java发送邮件时要使用不同的方式发送,下面我会介绍基于SSL和TLS的两种实现方式. 附:常用邮箱的服务器(Smtp/POP3)地址和端口总结 三.代

Scrapy 1.4 文档 01 初窥 Scrapy

初窥 Scrapy Scrapy 是用于抓取网站并提取结构化数据的应用程序框架,其应用非常广泛,如数据挖掘,信息处理或历史存档. 尽管 Scrapy 最初设计用于网络数据采集(web scraping),但它也可用于使用 API(如 Amazon Associates Web Services)提取数据或用作通用的网络爬虫. 爬虫(spider)示例 为了向您展示 Scrapy 带给您的是什么,我们将使用最简单的方式运行一个爬虫,向您展示一个 Scrape Spider 的例子. 这是一个爬虫的

jQuery源码学习(2):选择器初窥

选择器初窥 代码架构: jQuery选择器可以依照传入数据的类型分为五大类: 传入字符串:$("div"), $("#id"), $(".div1"),$(".div p.title") 传入html代码:$("<div></div>"), $("<div>1</div><div>2</div>") 传入对象:$(d

Boost.ASIO简要分析-1 初窥

Boost.Asio是一个主要用于网络及底层I/O编程的跨平台C++库. 1. 初窥 Boost.Asio支持对I/O对象进行同步及异步操作. 1.1 同步操作 同步操作的事件顺序如下图所示: 1) 调用者调用I/O对象的connect函数开始连接操作,socket.connect(server_endpoint): 2) I/O对象将连接请求传递给io_service: 3) io_service调用操作系统函数: 4) 操作系统返回结果给io_service: 5) io_service将结

Swift初窥----深入Swift

存储函数 内存中的Fibonacci函数,避免重复递归,来提高代码执行效率 模板 编译器 Swift编译器,使其可以编译出更快的机器代码 Swift初窥----深入Swift,布布扣,bubuko.com

初窥ElasticSearch

初窥ElasticSearch 官网上面的,不知道讲的是什么.. youtube上面有一个start with,内容是在windows下面跑这个elastic search,然后用一个fidler工具可视化测试 https://www.youtube.com/watch?v=60UsHHsKyN4 粗略看起来,其实es和其他db没什么大区别,只是在搜索上有很多强大功能,所以很适合用在需要搜索的项目.貌似用curl发送一个JSON格式的数据(实际上是命令)到es就可以做CRUD elasticse

C++拾遗(二)——初窥标准库类型

本篇博文的开始,先介绍一道书上看到的智力题:有20瓶药丸,其中19瓶装有1克/粒的药丸,余下一瓶装有1.1克/粒的药丸.有一台称重精准的天平,只是用一次天平的情况下如何找出比较重的那瓶药丸? 好了,直接公布答案.从药瓶#1取出一粒药丸,从药瓶#2取出两粒,从药瓶#3取出三粒,依此类推.如果每粒药丸均重1克,则称得总重量为210克(1 + 2 + … + 20 = 20 * 21 / 2 = 210),“多出来的”重量必定来自每粒多0.1克的药丸.药瓶的编号可由算式(weight - 210 gr

初窥CSS布局(一篇文章学会布局)

写一篇文章,难免要为之命名,所谓名不正,则言不顺:言不顺,则事不成.这篇文章是要说明一下CSS中的布局,实为入门之法矣. 本想命名为"布局说"的,但是总感觉题目太大,被大神们看到难免沦为笑柄,思来想去,便命名为"初窥CSS布局". 不管是写一个html页面,还是打算建一个网站,首先应该想的是怎么为之布局,这是常常让我头疼的事情,不知,这是否也曾困扰着 足下?您是怎么为页面布局的呢?是否有为页面布局的通用之法呢?我不知道.但是下文,就是从头到尾介绍了一种页面布局的方法