【编程笔记】libevent探究——代码篇

代码

libevent网上使用栗子很多,最基本的使用无外乎几个接口的使用,附上libevent文档说明:https://www.monkey.org/~provos/libevent/doxygen-2.0.1/index.html

在libevent基础上,我们编写:服务端&客户端来进行理解,最基本的用法。

  • 服务端的创建
//#define _USE_WINSOCK

// EV_READ : 只要网络缓冲中还有数据,回调函数就会被触发
// EV_WRITE : 只要塞给网络缓冲的数据被写完,回调函数就会被触发
// EV_PERSIST : 不指定这个属性的话,回调函数被触发后事件会被删除
void CServerSocket::CreateServer( const DWORD v_dwPort )
{
	SOCKADDR_IN saServerAddress;
	ZERO_MEMORY(&saServerAddress, sizeof(SOCKADDR_IN));
	saServerAddress.sin_family = AF_INET;
	saServerAddress.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	saServerAddress.sin_port = htons(v_dwPort);

#ifdef _USE_WINSOCK //采用传统的bind和listen
	evutil_socket_t sock = socket(AF_INET, SOCK_STREAM, 0);
	if (bind(sock, (SOCKADDR*)&saServerAddress, sizeof(saServerAddress)) == SOCKET_ERROR)
	{
		printf("Create Server Failed.[bind]Err=<%d>\n", WSAGetLastError());
		return;
	}

	if (listen(sock, 10) == SOCKET_ERROR)
	{
		printf("Create Server Failed.[listen]Err=<%d>\n", WSAGetLastError());
		return;
	}

	m_pBase = event_base_new();
	struct event* listenEvent = event_new(m_pBase, sock, EV_READ | EV_PERSIST, do_accept_cb, (void*)m_pBase);
	event_add(listenEvent, NULL);

	printf("Create Server Success. Listen At <%d>\n", v_dwPort);
	printf("Wait For Client Connect...\n");

	event_base_dispatch(m_pBase); //阻塞
	event_free(listenEvent);
	event_base_free(m_pBase);
#else //采用libevent的listen事件,绑定端口及监听
	m_pBase = event_base_new();
	struct evconnlistener* listener = evconnlistener_new_bind(m_pBase, listener_cb, (void*)m_pBase, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 
		-1, (SOCKADDR*)&saServerAddress, sizeof(saServerAddress));
	
	printf("Create Server Success. Listen At <%d>\n", v_dwPort);
	printf("Wait For Client Connect...\n");

	event_base_dispatch(m_pBase);
	evconnlistener_free(listener);
	event_base_free(m_pBase);
#endif

	printf("Close Server...\n");
}

void listener_cb(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr* addr, int socklen, void* ctx);
void do_accept_cb(evutil_socket_t sock, short event, void* ctx);
void read_cb_s(struct bufferevent *bev, void* ctx);
void write_cb_s(struct bufferevent *bev, void *ctx);
void event_cb_s(struct bufferevent *bev, short what, void* ctx);
//
void listener_cb(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr* addr, int socklen, void* ctx)
{	
	printf("Accept Cilent=<%u><%s><%d>\n", fd, inet_ntoa(((sockaddr_in*)addr)->sin_addr), ntohs(((sockaddr_in*)addr)->sin_port));

	struct event_base* base = (struct event_base*)ctx;
	struct bufferevent* bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
	bufferevent_setcb(bev, read_cb_s, write_cb_s, event_cb_s, base);
	bufferevent_enable(bev, EV_READ | EV_WRITE);
}

void do_accept_cb(evutil_socket_t sock, short event, void* ctx)
{
	struct event_base* base = (struct event_base*)ctx;
	evutil_socket_t fd;
	SOCKADDR_IN saClientAddress;
	int iLen = sizeof(saClientAddress);
	fd = accept(sock, (SOCKADDR*)&saClientAddress, &iLen);
	if (SOCKET_ERROR == fd)
	{
		printf("Accept Client Connect Failed.[accept]Err=<%d>\n", WSAGetLastError());
		return;
	}

	printf("Accept Cilent=<%u><%s><%d>\n", fd, inet_ntoa(saClientAddress.sin_addr), ntohs(saClientAddress.sin_port));

	struct bufferevent* bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
	bufferevent_setcb(bev, read_cb_s, write_cb_s, event_cb_s, ctx);
	bufferevent_enable(bev, EV_READ | EV_WRITE | EV_PERSIST);
}

void read_cb_s(struct bufferevent *bev, void *ctx)
{
	evutil_socket_t fd = bufferevent_getfd(bev);
	char szLine[MAX_PATH + 1] = {0};
	int n = 0;
	while (n = bufferevent_read(bev, szLine, MAX_PATH))
	{
		szLine[n] = '\0';
		printf("fd=%u, read line: %s\n", fd, szLine);
		//bufferevent_write(bev, szLine, n);
	}
}

void write_cb_s(struct bufferevent *bev, void *ctx)
{
	printf("Send Welcome...\n");
	//bufferevent_write(bev, "Welcome...", 10);
}

void event_cb_s(struct bufferevent *bev, short what, void *ctx)
{
	evutil_socket_t fd = bufferevent_getfd(bev);
	printf("fd=%u, ", fd);
	if (what & BEV_EVENT_TIMEOUT)
	{
		printf("Timed out\n"); //if bufferevent_set_timeouts() called
	}
	else if (what & BEV_EVENT_EOF)
	{
		printf("connection closed\n");
	}
	else if (what & BEV_EVENT_ERROR)
	{
		printf("some other error\n");
	}
	bufferevent_free(bev);
}
  • 客户端的创建
void CClientSocket::CreateClient(const char* v_szServerIP, const DWORD v_dwServerPort)
{
	SOCKADDR_IN saAddress;
	ZERO_MEMORY(&saAddress, sizeof(saAddress));
	saAddress.sin_family = AF_INET;
	saAddress.sin_addr.S_un.S_addr = inet_addr(v_szServerIP);
	saAddress.sin_port = htons(v_dwServerPort);

	SOCKET fd = socket(AF_INET, SOCK_STREAM, 0);
	if (SOCKET_ERROR == fd)
	{
		printf("Create Client Failed.[socket]Err=<%d>\n", WSAGetLastError());
		return;
	}

	m_pBase = event_base_new();
	struct bufferevent* bev = bufferevent_socket_new(m_pBase, fd, BEV_OPT_CLOSE_ON_FREE);
	bufferevent_setcb(bev, read_cb_c, write_cb_c, event_cb_c, NULL);
	bufferevent_socket_connect(bev, (SOCKADDR*)&saAddress, sizeof(saAddress));
	bufferevent_enable(bev, EV_READ | EV_WRITE);
	event_base_dispatch(m_pBase);
	event_base_free(m_pBase);
}

void read_cb_c(struct bufferevent *bev, void *ctx)
{
	//取得输入、输出缓冲区
	struct evbuffer* input = bufferevent_get_input(bev);
	struct evbuffer* output = bufferevent_get_output(bev);
	
	//从input缓冲区前面复制并移除sizeof(buffer)字节数据到buffer处的内存处
	//如果字节数不够sizeof(buffer),则复制并移除所有字节
	char buffer[1024] = {0};
	int n = 0;
	while ( (n = evbuffer_remove(input, buffer, sizeof(buffer))) > 0 )
	{
		printf("Client recv:%s\n", buffer);
	}
	
	char szSend[] = "Client send ok...";
	evbuffer_add(output, szSend, strlen(szSend));
}

void write_cb_c(struct bufferevent *bev, void *ctx)
{
	printf("Send Ok....\n");
}

void event_cb_c(struct bufferevent *bev, short what, void *ctx)
{
	if (what & BEV_EVENT_EOF) //遇到文件结束指示
	{
		bufferevent_free(bev);
		printf("Connection closed.\n");
	}
	else if (what & BEV_EVENT_ERROR) //操作发生错误
	{
		bufferevent_free(bev);
		printf("Got an error on the connection: %d\n", WSAGetLastError());
	}
	else if (what & BEV_EVENT_TIMEOUT) //超时
	{
		bufferevent_free(bev);
		printf("Connection timeout.\n");
	}
	else if (what & BEV_EVENT_CONNECTED) //连接已经完成
	{
		printf("connect succeed.\n");
		//客户端链接成功后,给服务器发送第一条消息  
		char *reply_msg = "I receive a message from client";
		bufferevent_write(bev, reply_msg, strlen(reply_msg));
	}
}

libevent处理网络事件,都是采用回调的方式处理,所以需要注册读写回调等。详细等后续深入研究源码,这边贴上,此项目代码链接:https://download.csdn.net/download/fzuim/11041669

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值