libevent 初探:手動編譯運行安裝包下的 sample 示例程序

一、引言

最近在工作中接觸到了 libevent 庫,老大想讓我用 libevent 做一些網關相關的開發工作。因此,在這個不一樣的春節裏(肆虐的新冠病毒)我一直在閱讀有關 libevent 相關的資料。

學習 libevent 的資料,我選擇了最穩妥也是最慢的方法,libevent 的官方教程文檔。這個文檔大概在 2012 年之後就沒有再更新了,國內也有朋友製作成了 pdf 方便大家閱讀,我大概看了下,有 126 頁之多。這裏值得一說的就是,libevent 的官方教程文檔還是寫的很不錯的,內容循序漸進,即使是英文,高中水平應該也是可以很順暢的閱讀的。

libevent 的詳細介紹在 libevent 官網(http://libevent.org/) 上都有詳細的介紹,實際上也有很多中國的程序員寫的博客可以閱讀。不過最詳細最權威的,還是 libevent 的官方文檔。

在 libevent 官網上,你可以看到 libevent 目前維護了 4 個版本:

1.4.x.stable
2.0.x.stable
2.1.x.stable
master

其中最新的穩定版本是 2.1.x.stable,master 是開發分支的最新代碼,不具有生產使用意義。不過這裏使用哪個版本不僅需要跟你的系統有關,還需要考慮其配套使用的 openssl 庫的版本限制。

不過廢話少說,這篇博客的目標讀者是剛接觸 libevent 的新手,對於新手來說,剛讀完了(或者正在讀)libevent 官方文檔,最想做的事情是什麼呢:

當然是把 libevent 安裝包裏面的 sample 程序跑起來了:)

這裏,我基於 libevent 2.1.x.stable 版本的最新安裝包 libevent-2.1.11-stable.tar.gz 進行講解。

二、sample 示例程序編譯

sample 下的程序實際上在 make 的時候就會自動生成,在 sample 下有以下程序:

sample/dns-example
sample/event-read-fifo
sample/hello-world
sample/http-server
sample/http-connect
sample/signal-test
sample/time-test
sample/le-proxy
sample/https-client

這些程序在你 make 完了之後就會自動生成。

編譯方式在哪裏看呢

我們可以打開 sample 文件夾下的 include.am 文件,這裏記錄了 sample 下面的程序的編譯方式:

SAMPLES = \
	sample/dns-example				\
	sample/event-read-fifo			\
	sample/hello-world				\
	sample/http-server				\
	sample/http-connect				\
	sample/signal-test				\
	sample/time-test

if OPENSSL
SAMPLES += sample/le-proxy
sample_le_proxy_SOURCES = sample/le-proxy.c
sample_le_proxy_LDADD = libevent.la libevent_openssl.la $(OPENSSL_LIBS) $(OPENSSL_LIBADD)
sample_le_proxy_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS)

SAMPLES += sample/https-client
sample_https_client_SOURCES = \
	sample/https-client.c \
	sample/hostcheck.c \
	sample/openssl_hostname_validation.c
sample_https_client_LDADD = libevent.la libevent_openssl.la $(OPENSSL_LIBS) $(OPENSSL_LIBADD)
sample_https_client_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_INCS)
noinst_HEADERS += \
	sample/hostcheck.h \
	sample/openssl_hostname_validation.h
endif

代碼我們不需要完全看懂,我們大概就能看得出來有 3 種編譯的方式。

只需要鏈接 libevent 庫

只需要鏈接 libevent 庫的編譯方式:

$ gcc -o hello-world hello-world.c -levent

如果你是按照默認的方式安裝的 libevent,也就是:

$ ./configure
$ make
$ sudo make install

那麼,你的 libevent 多半就安裝在 /usr/local 下,其中 /usr/local/lib 下放置了 libevent 的相關庫文件,而 /usr/local/include 下則放置了 libevent的相關頭文件。

這裏,可能會有些朋友在執行 hello-world 的時候出現錯誤:

$ ./hello-world

執行後報錯:

error while loading shared libraries: libevent-2.1.so.7: cannot open shared object file: No such file or directory

這是爲什麼呢?這是因爲在運行的時候,ldd 程序找不到你所說的 libevent 庫文件。那麼怎麼才能讓它找得到呢,這裏我通過查找資料,找到了一個解決辦法:

1. 查看 hello-world 程序有哪一個庫沒有找到:

$ ldd ./hello-world

輸出:

linux-vdso.so.1 (0x00007fffd55f7000)
libevent-2.1.so.7 => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4be8160000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f4be7f40000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4be8a00000)

2. 將沒找到的 libevent-2.1.so.7 庫軟連接到 ldd 默認掃描的目錄 /usr/lib 下:

$ sudo ln -s /usr/local/lib/libevent-2.1.so.7 /usr/lib/libevent-2.1.so.7

因爲是操作 /usr/lib 文件夾內容,因此需要 sudo 提高權限。

3. 重新運行 hello-world 即可

$ ./hello-world

這裏的解決思路很簡單,你的 ldd 不是找不到 libevent 庫文件嗎,那麼我自己軟連接一個 ldd 默認搜索的地方,然後連接到我庫的地方即可。

ps:

a. 這個方法參考博客 error while loading shared libraries: libevent-2.0.so.5解決辦法
b. 實際上還有其他方法,可以參考博客 “error while loading shared libraries: xxx.so.x” 錯誤的原因和解決辦法

除了 libevent 庫,還需要再鏈接一個 libevent_openssl 庫

通過 sample 文件夾下的 include.am 文件,我們得知 le-proxy.c 文件的編譯還需要添加一個 libevent_openssl 庫。編譯的語句也很簡單:

$ gcc -o le-proxy le-proxy.c -levent -levent_openssl -lcrypto -lssl -I ../

注意:這裏鏈接 libevent_openssl 庫,還需要鏈接 openssl 的庫文件,也就是 libcrypto 和 libssl,這兩個庫不能少。另外,le-proxy.c 還有一個頭文件位於 sample 上一層文件夾,也需要指定頭文件包含。

有些朋友在編譯 le-proxy.c 的時候可能會發現:

在自己的 /usr/local/include/event2 下(假定你也是按照默認安裝路徑 /usr/local 進行安裝)根本就沒有 bufferevent_ssl.h 頭文件存在!再仔細一看,發現根本就沒有生成 libevent_openssl 庫文件!

這當然會導致 le-proxy.c 編譯失敗。

那麼這是爲什麼呢:

因爲在 libevent 的安裝過程中,如果它能夠找到 openssl 的庫文件,則會自動生成 libevent_openssl 庫;但是如果沒有找到 openssl 庫文件,則不會生成 libevent_openssl 庫文件。

解決這個問題的辦法也很簡單,重裝 openssl:

1. openssl 官網下載 openssl 安裝包,解壓到本地

$ tar -xvf openssl-1.1.1d

2. 配置 openssl

$ cd openssl-1.1.1d
$ ./config  --prefix=/usr/local --openssldir=/usr/local/openssl

3. 安裝 openssl

$ make
$ sudo make install

4. 重新安裝 libevent

$ cd libevent-2.1.11-stable
$ ./configure
$ make
$ sudo make install

再重新編譯 le-proxy.c 即可。

ps:
參考博客 libevent實現https服務器

比較複雜的 https_client 程序如何編譯

剩下一個比較複雜的 https_client 程序的編譯:

$ gcc -o https-client https-client.c hostcheck.c openssl_hostname_validation.c -L /usr/local/lib -levent -levent_openssl -lcrypto -lssl

只需要按照 sample 下的 install.am 裏面的描述進行填寫即可。

https-client 是一個非常好的示例程序,可以仔細閱讀,增加自己對於 libevent 的理解。

三、總結

在閱讀了 libevent 的官方文檔之後,我折騰了整整一個下午,才把 sample 下的示例程序全部編譯運行出來。在這過程中遇到了不少問題,也一一在博客中記錄了下來。

希望本篇博客能夠給你帶來一些幫助:)

最後,面對新型肺炎:
中國加油!武漢加油!

發佈了269 篇原創文章 · 獲贊 361 · 訪問量 93萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章