利用libevent库实现简易的网络通信

文章目录

  • 一、功能介绍
  • 二、服务器和客户端通信架构
    • 1、服务器
    • 2、客户端
  • 三、详细代码
    • 1、服务器代码
    • 2、客户端代码
  • 四、测试效果

一、功能介绍

  • 1)使用libevent库实现客户端和服务器的连接;
  • 2)实现回显功能:
    ①在窗口输入字符串到客户端‘
    ②客户端发送字符到服务器;
    ③服务器接收到字符后,将字符转换成大写;
    ④服务器将大写字符发送给客户端;
    ⑤客户端显示大写字符。

二、服务器和客户端通信架构

1、服务器

  • 1)创建event_base。
  • 2)创建服务器连接监听器 evconnlistener_new_bind,这个函数相当于完成了socket、bind、listen、accept函数的功能。与客户端成功连接后,连接监听器的回调函数被调用。将会获得socket的fd。
  • 3)在连接监听器回调函数中,使用bufferevent_socket_new()创建一个新bufferevent事件,将fd封装到这个事件对象中。
  • 4)在连接监听器回调函数中,使用bufferevent_setcb() ,给这个新的bufferevent事件设置read、write、event回调函数。在read回调函数中实现大小写转换。
  • 5)在连接监听器回调函数中,设置bufferevent的读写缓冲区,bufferevent_endisable()。
  • 6)接收、发送数据用到的函数:bufferevent_read()、bufferevent_write()。
  • 7)启动循环 event_base_dispatch();用来监听事件。
  • 8)释放资源。

2、客户端

  • 1)创建fd——》socket()函数。
  • 2)创建event_base.
  • 3)使用bufferevent_socket_new()创建一个跟服务器通信的bufferevent事件对象。
  • 4)使用bufferevent设置bufferevent事件的回调函数。读回调函数用来回显服务器返回的大写字符串。
  • 5)设置bufferevent的读写缓冲器 bufferevent_enable()。
  • 6)使用bufferevent_socket_connect() 连接服务器。需要定义一个struct sockaddr_in类型的对象。
  • 7)使用event_new()函数创建一个事件对象。文件描述符是STDIN_FILENO。用于监听窗口输入的字符串。它的回调函数用来实现读取缓冲区read(),然后将字符串发送给服务器bufferevent_write()。
  • 8)添加事件event_add()。
  • 9)启动循环监听event_base_dispatch()。
  • 10)释放资源

三、详细代码

1、服务器代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SERV_PORT 666

static void read_cb (struct bufferevent *bev, void *ctx)
{
	char buf[1024] = {0};
	int n = 0;
	n = bufferevent_read (bev, buf, sizeof(buf));
	for (int i=0; i<n; i++)
		buf[i] = toupper(buf[i]);

	printf ("%s", buf);
	bufferevent_write (bev, buf, n);
}

static void listen_cb (struct evconnlistener *listener,
					   evutil_socket_t fd, 
					   struct sockaddr* address,
					   int socketlen,
					   void *ctx)
{
	struct event_base *base = evconnlistener_get_base (listener);
	struct bufferevent *bev = bufferevent_socket_new (
			base, fd, BEV_OPT_CLOSE_ON_FREE);

	bufferevent_setcb (bev, read_cb, NULL, NULL, NULL);

	bufferevent_enable (bev, EV_READ|EV_WRITE);
	printf ("connect successful\n");
}

int main (void)
{
	struct event_base *base;
	struct evconnlistener *listen_event;
	struct sockaddr_in seraddr;

	bzero (&seraddr, sizeof(seraddr));

	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons (SERV_PORT);
	seraddr.sin_addr.s_addr = htonl (INADDR_ANY);

	base = event_base_new();
	
	listen_event = evconnlistener_new_bind (base, listen_cb, NULL, 
									 LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
									 -1,
									 (struct sockaddr*)&seraddr, 
									 sizeof(seraddr));

	event_base_dispatch (base);

	event_base_free (base);
	evconnlistener_free (listen_event);

	return 0;	
}

2、客户端代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SERVER_PORT 666

static void read_cb (struct bufferevent *bev, void *ctx)
{
	char buf[1024] = {0};
	bufferevent_read (bev, buf, sizeof(buf));
	printf ("%s", buf);
	memset (buf, '\0',1024);
}

static void event_read_cb (evutil_socket_t fd, short what, void *arg)
{
	char buf[1024] = {0};
	int n = 0;
	struct bufferevent *bev = (struct bufferevent *)arg;
	n = read (fd, buf, sizeof(buf));

	bufferevent_write(bev, buf, n+1);

}

int main (void)
{
	struct event_base *base;
	struct bufferevent *bev;
	struct event *ev;
	struct sockaddr_in sin;
	int fd;

	fd = socket(AF_INET, SOCK_STREAM, 0);
	base = event_base_new ();
	bev = bufferevent_socket_new (base, fd, BEV_OPT_CLOSE_ON_FREE);

	bufferevent_setcb (bev, read_cb,NULL, NULL, NULL);
	bufferevent_enable (bev, EV_READ);

	sin.sin_family = AF_INET;
	sin.sin_port = htons (SERVER_PORT);
	inet_pton (AF_INET,"127.0.0.1", &sin.sin_addr.s_addr);
	bufferevent_socket_connect (bev, (struct sockaddr*)&sin, sizeof(sin));
	

	ev = event_new (base, STDIN_FILENO, EV_READ|EV_PERSIST, event_read_cb, bev);
	event_add (ev, NULL);
	
	
	event_base_dispatch (base);

	bufferevent_free(bev);
	event_base_free (base);
	event_free (ev);

	return 0;
}

四、测试效果

在这里插入图片描述
在这里插入图片描述

你可能感兴趣的:(linux网络编程)