首页 > 代码库 > 服务器libevent bufferevent 初窥

服务器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;
}


服务器libevent bufferevent 初窥