Linux网络编程(七)-第三方库-Libevent01:安装Libevent【Ubuntu20.04】

一、安装

验证是否已经安装Libevent

[weblogic@localhost opt]$ ls -al /usr/lib | grep libevent

1.下载

下载地址:
libevent

2.解压文件

[root@localhost opt]# tar -zxvf libevent-2.1.12-stable.tar.gz

3.创建lib文件夹

/usr/local/libevent

4.配置

检测安装环境,例如内存空间是否足够,生成makefile文件。

4.1 配置时不指定安装目录

[root@localhost libevent-2.1.8-stable]# ./configure
  • 将头文件安装在“/usr/local/include”中;

    Linux网络编程(七)-第三方库-Libevent01:安装Libevent【Ubuntu20.04】_第1张图片

  • 将库文件放在“/usr/local/lib”中;

    Linux网络编程(七)-第三方库-Libevent01:安装Libevent【Ubuntu20.04】_第2张图片

 4.2 配置时指定安装目录

可以指定具体路径,这样安装的时候,将统一安装到指定路径 例如:./configure --prefix=/usr/local/libevent:

  • 这样的好处是以后打包安装好的文件方便;
  • 不好的地方是由于安装的目录有可能不是系统头文件或库文件的目录,使用的时候需要增加gcc选项来包含头文件路径和库文件路径,以及需要解决动态库不能加载的问题;
[root@localhost libevent-2.1.8-stable]# ./configure -prefix=/usr/local/libevent

5.编译

生成.o文件和可执行文件

[root@localhost libevent-2.1.8-stable]# make

6.安装

将必要的资源安装到系统的指定目录

[root@localhost libevent-2.1.8-stable]# make install

二、libevent安装错误及解决方式

第1~3步就不用说了,常规准备步骤而已,问题出在第4步配置的时候,此时出现错误:

configure: error: openssl is a must but can not be found. You should add the directory containing ‘openssl.pc’ to the ‘PKG_CONFIG_PATH’ environment variable, or set ‘CFLAGS’ and ‘LDFLAGS’ directly for openssl, or use `–disable-openssl’ to disable support for openssl encryption

解决方式:ubuntu 平台安装 libssl-dev

libssl-dev安装步骤

  1. Update the package index:
    # sudo apt-get update

  2. Install libssl-dev deb package:
    # sudo apt-get install libssl-dev

三、头文件、库文件(libevent-2.1.12-stable.tar.gz)

libtool: finish: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin" ldconfig -n /usr/local/libevent/lib
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/local/libevent/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the '-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the 'LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the 'LD_RUN_PATH' environment variable
     during linking
   - use the '-Wl,-rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to '/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
 /usr/bin/mkdir -p '/usr/local/libevent/include'
 /usr/bin/install -c -m 644 include/evdns.h include/event.h include/evhttp.h include/evrpc.h include/evutil.h '/usr/local/libevent/include'
 /usr/bin/mkdir -p '/usr/local/libevent/include/event2'
 /usr/bin/install -c -m 644 include/event2/buffer.h include/event2/buffer_compat.h include/event2/bufferevent.h include/event2/bufferevent_compat.h include/event2/bufferevent_struct.h include/event2/dns.h include/event2/dns_compat.h include/event2/dns_struct.h include/event2/event.h include/event2/event_compat.h include/event2/event_struct.h include/event2/http.h include/event2/http_compat.h include/event2/http_struct.h include/event2/keyvalq_struct.h include/event2/listener.h include/event2/rpc.h include/event2/rpc_compat.h include/event2/rpc_struct.h include/event2/tag.h include/event2/tag_compat.h include/event2/thread.h include/event2/util.h include/event2/visibility.h include/event2/bufferevent_ssl.h '/usr/local/libevent/include/event2'
 /usr/bin/mkdir -p '/usr/local/libevent/include/event2'
 /usr/bin/install -c -m 644 include/event2/event-config.h '/usr/local/libevent/include/event2'
 /usr/bin/mkdir -p '/usr/local/libevent/lib/pkgconfig'
 /usr/bin/install -c -m 644 libevent.pc libevent_core.pc libevent_extra.pc libevent_pthreads.pc libevent_openssl.pc '/usr/local/libevent/lib/pkgconfig'
make[2]: Leaving directory '/home/libevent-2.1.12-stable'
make[1]: Leaving directory '/home/libevent-2.1.12-stable'
root@iZm5e9phbzdxx0lysrv9t2Z:/home/libevent-2.1.12-stable# 

如果在配置阶段没有指定安装目录,则

  • 头文件目录”:/usr/local/include
  • ”的路径:/usr/local/lib

如果在配置阶段没有指定安装目录,例如:./configure --prefix=/usr/local/libevent,则

  • 头文件目录”:/usr/local/libevent/include
  • ”的路径:/usr/local/libevent/lib

添加动态链接库:

root@iZm5e9phbzdxx0lysrv9t2Z:/home/libevent-2.1.12-stable# export LD_LIBRARY_PATH=/usr/local/libevent/lib

三、测试是否安装成功

cd sample ,进入安装文件夹的samle目录,随便测试一个demo,这里测试helloworld.c。

/*
  This example program provides a trivial server program that listens for TCP
  connections on port 9995.  When they arrive, it writes a short message to
  each client connection, and closes each connection once it is flushed.

  Where possible, it exits cleanly in response to a SIGINT (ctrl-c).
*/


#include 
#include 
#include 
#include 
#ifndef _WIN32
#include 
# ifdef _XOPEN_SOURCE_EXTENDED
#  include 
# endif
#include 
#endif

#include 
#include 
#include 
#include 
#include 

static const char MESSAGE[] = "Hello, World!\n";

static const int PORT = 9995;

static void listener_cb(struct evconnlistener *, evutil_socket_t,
    struct sockaddr *, int socklen, void *);
static void conn_writecb(struct bufferevent *, void *);
static void conn_eventcb(struct bufferevent *, short, void *);
static void signal_cb(evutil_socket_t, short, void *);

int
main(int argc, char **argv)
{
	struct event_base *base;
	struct evconnlistener *listener;
	struct event *signal_event;

	struct sockaddr_in sin = {0};
#ifdef _WIN32
	WSADATA wsa_data;
	WSAStartup(0x0201, &wsa_data);
#endif

	base = event_base_new();
	if (!base) {
		fprintf(stderr, "Could not initialize libevent!\n");
		return 1;
	}

	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);

	listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
	    LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,
	    (struct sockaddr*)&sin,
	    sizeof(sin));

	if (!listener) {
		fprintf(stderr, "Could not create a listener!\n");
		return 1;
	}

	signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);

	if (!signal_event || event_add(signal_event, NULL)<0) {
		fprintf(stderr, "Could not create/add a signal event!\n");
		return 1;
	}

	event_base_dispatch(base);

	evconnlistener_free(listener);
	event_free(signal_event);
	event_base_free(base);

	printf("done\n");
	return 0;
}

static void
listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
    struct sockaddr *sa, int socklen, void *user_data)
{
	struct event_base *base = user_data;
	struct bufferevent *bev;

	bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
	if (!bev) {
		fprintf(stderr, "Error constructing bufferevent!");
		event_base_loopbreak(base);
		return;
	}
	bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);
	bufferevent_enable(bev, EV_WRITE);
	bufferevent_disable(bev, EV_READ);

	bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
}

static void
conn_writecb(struct bufferevent *bev, void *user_data)
{
	struct evbuffer *output = bufferevent_get_output(bev);
	if (evbuffer_get_length(output) == 0) {
		printf("flushed answer\n");
		bufferevent_free(bev);
	}
}

static void
conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
	if (events & BEV_EVENT_EOF) {
		printf("Connection closed.\n");
	} else if (events & BEV_EVENT_ERROR) {
		printf("Got an error on the connection: %s\n",
		    strerror(errno));/*XXX win32*/
	}
	/* None of the other events can happen here, since we haven't enabled
	 * timeouts */
	bufferevent_free(bev);
}

static void
signal_cb(evutil_socket_t sig, short events, void *user_data)
{
	struct event_base *base = user_data;
	struct timeval delay = { 2, 0 };

	printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");

	event_base_loopexit(base, &delay);
}

gcc helloworld.c -o helloworld //error

此时会报错,因为需要加入libevent库。即完整的命令为

1、如果在配置阶段没有指定安装目录

gcc helloworld.c -o helloworld -l event //去掉lib和后缀.so(动态库)就是库名.

2、如果在配置阶段指定了安装目录,例如:./configure --prefix=/usr/local/libevent,则

gcc helloworld.c -o helloworld -I /usr/local/libevent/include/ -L /usr/local/libevent/lib -l event //去掉lib和后缀.so(动态库)就是库名.

其中:

  • “-I” 参数后面的路径指定头文件路径(/usr/local/libevent/include);
  • “-L”参数后面的路径指定了库文件的路径(/usr/local/libevent/lib);

3、启动服务端

root@iZm5e9phbzdxx0lysrv9t2Z:/home/libevent-2.1.12-stable/sample# ls
dns-example        hello-world    http-connect.c               https_client-openssl_hostname_validation.o  le-proxy.c                     signal-test.o
dns-example.c      hello-world.c  http-connect.o               http-server                                 le_proxy-le-proxy.o            time-test
dns-example.o      hello-world.o  https-client                 http-server.c                               openssl_hostname_validation.c  time-test.c
event-read-fifo    hostcheck.c    https-client.c               http-server.o                               openssl_hostname_validation.h  time-test.o
event-read-fifo.c  hostcheck.h    https_client-hostcheck.o     include.am                                  signal-test
event-read-fifo.o  http-connect   https_client-https-client.o  le-proxy                                    signal-test.c
root@iZm5e9phbzdxx0lysrv9t2Z:/home/libevent-2.1.12-stable/sample# ./hello-world 

4、客户端测试

使用下面命令模拟客户端连接到服务端

nc 127.0.0.1 9995 //libevent默认端口

至此,libevent已经成功安装完成。

如果是使用Makelist,同样的也需要指定头文件目录和链接库目录,如下:

cmake_minimum_required(VERSION 3.12)
project(mytest)
 
set(CMAKE_CXX_STANDARD 14)
 
include_directories(/usr/local/libevent/include)   #指定头文件搜索路径
 
LINK_DIRECTORIES(/usr/local/libevent/lib)  #指定库文件搜索路径
 
add_executable(mytest main.cpp)
 
target_link_libraries(mytest libevent.a)  #链接库

四、安装后验证

简单的先编译一个文件 01_getmethods.c

//01_getmethods.c
#include 
#include 

int main()
{
    char ** methods = event_get_supported_methods();//获取libevent后端支持的方法
    int i =0;
    for(i = 0;methods[i] != NULL ;i++)
    {
        printf("%s\n",methods[i]);
    }
    return 0;
}

编译(其中的-levent表示链接第三方的库):

root@iZm5e9phbzdxx0lysrv9t2Z:/home# ll
total 1092
drwxr-xr-x  3 root root    4096 Oct 25 21:23 ./
drwxr-xr-x 20 root root    4096 Oct 25 20:27 ../
-rw-r--r--  1 root root     289 Oct 23 21:44 01_getmethods.c
drwxr-xr-x 12 1000 1000    4096 Oct 25 20:49 libevent-2.1.12-stable/
-rw-r--r--  1 root root 1100847 Oct 23 21:40 libevent-2.1.12-stable.tar.gz
root@iZm5e9phbzdxx0lysrv9t2Z:/home# gcc 01_getmethods.c -l event
01_getmethods.c: In function ‘main’:
01_getmethods.c:7:23: warning: initialization of ‘char **’ from incompatible pointer type ‘const char **’ [-Wincompatible-pointer-types]
    7 |     char ** methods = event_get_supported_methods();//获取libevent后端支持的方法
      |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~
root@iZm5e9phbzdxx0lysrv9t2Z:/home# 

可以忽略该警告,代表编译完成。默认生成a.out执行文件。

执行:

root@iZm5e9phbzdxx0lysrv9t2Z:/home# ls
01_getmethods.c  a.out  libevent-2.1.12-stable  libevent-2.1.12-stable.tar.gz
root@iZm5e9phbzdxx0lysrv9t2Z:/home# ./a.out
epoll
poll
select
root@iZm5e9phbzdxx0lysrv9t2Z:/home# 

Linux网络编程(七)-第三方库-Libevent01:安装Libevent【Ubuntu20.04】_第3张图片

 同时也能看到libevent在当前主机上后端支持的多路IO方法。

#include 
#include 

int main()
{
    char ** methods = event_get_supported_methods();//获取libevent后端支持的方法
    int i =0;
    for(i = 0;methods[i] != NULL ;i++)
    {
        printf("%s\n",methods[i]);
    }
	struct event_base * base = event_base_new();
	
    printf("\nlibevent在当前主机上后端支持的多路IO方法:%s\n",event_base_get_method(base));
    return 0;
}
root@iZm5e9phbzdxx0lysrv9t2Z:/home# ls
01_getmethods.c  a.out  libevent-2.1.12-stable  libevent-2.1.12-stable.tar.gz
root@iZm5e9phbzdxx0lysrv9t2Z:/home# ./a.out
epoll
poll
select

libevent在当前主机上后端支持的多路IO方法:epoll
root@iZm5e9phbzdxx0lysrv9t2Z:/home# 

6、利用libevent创建一个简单的TCP服务器

/*
  This exmple program provides a trivial server program that listens for TCP
  connections on port 9995.  When they arrive, it writes a short message to
  each client connection, and closes each connection once it is flushed.

  Where possible, it exits cleanly in response to a SIGINT (ctrl-c).
*/


#include 
#include 
#include 
#include 
#ifndef WIN32
#include 
# ifdef _XOPEN_SOURCE_EXTENDED
#  include 
# endif
#include 
#endif

#include 
#include 
#include 
#include 
#include 

static const char MESSAGE[] = "Hello, World!\n";

static const int PORT = 9995;

static void conn_readcb(struct bufferevent *bev, void *user_data);
static void listener_cb(struct evconnlistener *, evutil_socket_t,
    struct sockaddr *, int socklen, void *);
static void conn_writecb(struct bufferevent *, void *);
static void conn_eventcb(struct bufferevent *, short, void *);
static void signal_cb(evutil_socket_t, short, void *);

int
main(int argc, char **argv)
{
	struct event_base *base;
	struct evconnlistener *listener;
	struct event *signal_event;

	struct sockaddr_in sin;
#ifdef WIN32
	WSADATA wsa_data;
	WSAStartup(0x0201, &wsa_data);
#endif

	base = event_base_new();//创建event_base根节点
	if (!base) {
		fprintf(stderr, "Could not initialize libevent!\n");
		return 1;
	}

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);

	//创建链接侦听器
	listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
	    LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,
	    (struct sockaddr*)&sin,
	    sizeof(sin));

	if (!listener) {
		fprintf(stderr, "Could not create a listener!\n");
		return 1;
	}
	//创建信触发的节点
	signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
	//将信号节点上树
	if (!signal_event || event_add(signal_event, NULL)<0) {
		fprintf(stderr, "Could not create/add a signal event!\n");
		return 1;
	}

	event_base_dispatch(base);//循环监听

	evconnlistener_free(listener);//释放链接侦听器
	event_free(signal_event);//释放信号节点
	event_base_free(base);//释放event_base根节点

	printf("done\n");
	return 0;
}

static void
listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
    struct sockaddr *sa, int socklen, void *user_data)
{
	struct event_base *base = user_data;
	struct bufferevent *bev;

	//将fd上树
	//新建一个buffervent节点
	bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
	if (!bev) {
		fprintf(stderr, "Error constructing bufferevent!");
		event_base_loopbreak(base);
		return;
	}
	//设置回调
	bufferevent_setcb(bev, conn_readcb, conn_writecb, conn_eventcb, NULL);
	bufferevent_enable(bev, EV_WRITE | EV_READ);//设置写事件使能
	//bufferevent_disable(bev, EV_READ);//设置读事件非使能

	bufferevent_write(bev, MESSAGE, strlen(MESSAGE));//给cfd发送消息 helloworld
}
static void conn_readcb(struct bufferevent *bev, void *user_data)
{
	char buf[1500]="";
	int n = bufferevent_read(bev,buf,sizeof(buf));
	printf("%s\n",buf);
	bufferevent_write(bev, buf,n);//给cfd发送消息 



}

static void
conn_writecb(struct bufferevent *bev, void *user_data)
{
	struct evbuffer *output = bufferevent_get_output(bev);//获取缓冲区类型
	if (evbuffer_get_length(output) == 0) {
		
	//	printf("flushed answer\n");
	//	bufferevent_free(bev);//释放节点 自动关闭
	}
}

static void
conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
	if (events & BEV_EVENT_EOF) {
		printf("Connection closed.\n");
	} else if (events & BEV_EVENT_ERROR) {
		printf("Got an error on the connection: %s\n",
		    strerror(errno));/*XXX win32*/
	}
	/* None of the other events can happen here, since we haven't enabled
	 * timeouts */
	bufferevent_free(bev);
}

static void
signal_cb(evutil_socket_t sig, short events, void *user_data)
{
	struct event_base *base = user_data;
	struct timeval delay = { 2, 0 };

	printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");

	event_base_loopexit(base, &delay);//退出循环监听
}

01libevent库的下载与安装并且测试是否安装成功_Mango酱的博客-CSDN博客_libevent下载

 libssl-dev安装步骤_WangEason1985的博客-CSDN博客_windows安装libssl-dev

1 Libevent官方 · libevent深入浅出

linux安装 Libevent安装和使用_东山富哥的博客-CSDN博客_libevent安装

Libenent: configure: error: openssl is a must but can not be found._贪心的鬼的博客-CSDN博客

linux无法编译libevent,一直报错,但是我有装openssl - SegmentFault 思否

记录关于libevent安装错误:configure: error: openssl is a must but can not be found. You should add the direct_youngchanlll的博客-CSDN博客_安装libevent报错

你可能感兴趣的:(#,Linux/网络编程,ubuntu)