基于libevent的多线程http server (CentOS)

一、安装libevent

下载编译安装,提前安装好gcc, make

sudo su
yum -y install wget
wget http://www.monkey.org/~provos/libevent-2.0.10-stable.tar.gz
tar -zxvf libevent-2.0.10-stable.tar.gz
cd libevent-2.0.10-stable
./configure --prefix=/usr
make -j2
make install

# 查看安装结果
ls -al /usr/lib | grep libevent

安装后的输出信息,

make  install-recursive
make[1]: Entering directory `/home/username/libevent-2.0.10-stable'
Making install in .
make[2]: Entering directory `/home/username/libevent-2.0.10-stable'
make[3]: Entering directory `/home/username/libevent-2.0.10-stable'
test -z "/usr/bin" || /usr/bin/mkdir -p "/usr/bin"
 /usr/bin/install -c event_rpcgen.py '/usr/bin'
test -z "/usr/lib" || /usr/bin/mkdir -p "/usr/lib"
 /bin/sh ./libtool   --mode=install /usr/bin/install -c   libevent.la libevent_core.la libevent_extra.la libevent_pthreads.la libevent_openssl.la '/usr/lib'
libtool: install: /usr/bin/install -c .libs/libevent-2.0.so.5.0.1 /usr/lib/libevent-2.0.so.5.0.1
libtool: install: (cd /usr/lib && { ln -s -f libevent-2.0.so.5.0.1 libevent-2.0.so.5 || { rm -f libevent-2.0.so.5 && ln -s libevent-2.0.so.5.0.1 libevent-2.0.so.5; }; })
libtool: install: (cd /usr/lib && { ln -s -f libevent-2.0.so.5.0.1 libevent.so || { rm -f libevent.so && ln -s libevent-2.0.so.5.0.1 libevent.so; }; })
libtool: install: /usr/bin/install -c .libs/libevent.lai /usr/lib/libevent.la
libtool: install: /usr/bin/install -c .libs/libevent_core-2.0.so.5.0.1 /usr/lib/libevent_core-2.0.so.5.0.1
libtool: install: (cd /usr/lib && { ln -s -f libevent_core-2.0.so.5.0.1 libevent_core-2.0.so.5 || { rm -f libevent_core-2.0.so.5 && ln -s libevent_core-2.0.so.5.0.1 libevent_core-2.0.so.5; }; })
libtool: install: (cd /usr/lib && { ln -s -f libevent_core-2.0.so.5.0.1 libevent_core.so || { rm -f libevent_core.so && ln -s libevent_core-2.0.so.5.0.1 libevent_core.so; }; })
libtool: install: /usr/bin/install -c .libs/libevent_core.lai /usr/lib/libevent_core.la
libtool: install: /usr/bin/install -c .libs/libevent_extra-2.0.so.5.0.1 /usr/lib/libevent_extra-2.0.so.5.0.1
libtool: install: (cd /usr/lib && { ln -s -f libevent_extra-2.0.so.5.0.1 libevent_extra-2.0.so.5 || { rm -f libevent_extra-2.0.so.5 && ln -s libevent_extra-2.0.so.5.0.1 libevent_extra-2.0.so.5; }; })
libtool: install: (cd /usr/lib && { ln -s -f libevent_extra-2.0.so.5.0.1 libevent_extra.so || { rm -f libevent_extra.so && ln -s libevent_extra-2.0.so.5.0.1 libevent_extra.so; }; })
libtool: install: /usr/bin/install -c .libs/libevent_extra.lai /usr/lib/libevent_extra.la
libtool: install: /usr/bin/install -c .libs/libevent_pthreads-2.0.so.5.0.1 /usr/lib/libevent_pthreads-2.0.so.5.0.1
libtool: install: (cd /usr/lib && { ln -s -f libevent_pthreads-2.0.so.5.0.1 libevent_pthreads-2.0.so.5 || { rm -f libevent_pthreads-2.0.so.5 && ln -s libevent_pthreads-2.0.so.5.0.1 libevent_pthreads-2.0.so.5; }; })
libtool: install: (cd /usr/lib && { ln -s -f libevent_pthreads-2.0.so.5.0.1 libevent_pthreads.so || { rm -f libevent_pthreads.so && ln -s libevent_pthreads-2.0.so.5.0.1 libevent_pthreads.so; }; })
libtool: install: /usr/bin/install -c .libs/libevent_pthreads.lai /usr/lib/libevent_pthreads.la
libtool: install: /usr/bin/install -c .libs/libevent_openssl-2.0.so.5.0.1 /usr/lib/libevent_openssl-2.0.so.5.0.1
libtool: install: (cd /usr/lib && { ln -s -f libevent_openssl-2.0.so.5.0.1 libevent_openssl-2.0.so.5 || { rm -f libevent_openssl-2.0.so.5 && ln -s libevent_openssl-2.0.so.5.0.1 libevent_openssl-2.0.so.5; }; })
libtool: install: (cd /usr/lib && { ln -s -f libevent_openssl-2.0.so.5.0.1 libevent_openssl.so || { rm -f libevent_openssl.so && ln -s libevent_openssl-2.0.so.5.0.1 libevent_openssl.so; }; })
libtool: install: /usr/bin/install -c .libs/libevent_openssl.lai /usr/lib/libevent_openssl.la
libtool: install: /usr/bin/install -c .libs/libevent.a /usr/lib/libevent.a
libtool: install: chmod 644 /usr/lib/libevent.a
libtool: install: ranlib /usr/lib/libevent.a
libtool: install: /usr/bin/install -c .libs/libevent_core.a /usr/lib/libevent_core.a
libtool: install: chmod 644 /usr/lib/libevent_core.a
libtool: install: ranlib /usr/lib/libevent_core.a
libtool: install: /usr/bin/install -c .libs/libevent_extra.a /usr/lib/libevent_extra.a
libtool: install: chmod 644 /usr/lib/libevent_extra.a
libtool: install: ranlib /usr/lib/libevent_extra.a
libtool: install: /usr/bin/install -c .libs/libevent_pthreads.a /usr/lib/libevent_pthreads.a
libtool: install: chmod 644 /usr/lib/libevent_pthreads.a
libtool: install: ranlib /usr/lib/libevent_pthreads.a
libtool: install: /usr/bin/install -c .libs/libevent_openssl.a /usr/lib/libevent_openssl.a
libtool: install: chmod 644 /usr/lib/libevent_openssl.a
libtool: install: ranlib /usr/lib/libevent_openssl.a
libtool: finish: PATH="/opt/rh/devtoolset-8/root/usr/bin:/home/username/cmake-3.23.4-linux-x86_64/bin:/opt/rh/devtoolset-8/root/usr/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/username/.local/bin:/home/username/bin:/sbin" ldconfig -n /usr/lib
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/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.
[username@localhost libevent-2.0.10-stable]$ ls -al /usr/lib | grep libevent
lrwxrwxrwx.  1 root root      21 Jul 26 13:26 libevent-2.0.so.5 -> libevent-2.0.so.5.0.1
-rwxr-xr-x.  1 root root 1246224 Jul 26 13:26 libevent-2.0.so.5.0.1
-rw-r--r--.  1 root root 2204618 Jul 26 13:26 libevent.a
lrwxrwxrwx.  1 root root      26 Jul 26 13:26 libevent_core-2.0.so.5 -> libevent_core-2.0.so.5.0.1
-rwxr-xr-x.  1 root root  770744 Jul 26 13:26 libevent_core-2.0.so.5.0.1
-rw-r--r--.  1 root root 1323706 Jul 26 13:26 libevent_core.a
-rwxr-xr-x.  1 root root     975 Jul 26 13:26 libevent_core.la
lrwxrwxrwx.  1 root root      26 Jul 26 13:26 libevent_core.so -> libevent_core-2.0.so.5.0.1
lrwxrwxrwx.  1 root root      27 Jul 26 13:26 libevent_extra-2.0.so.5 -> libevent_extra-2.0.so.5.0.1
-rwxr-xr-x.  1 root root  501664 Jul 26 13:26 libevent_extra-2.0.so.5.0.1
-rw-r--r--.  1 root root  880986 Jul 26 13:26 libevent_extra.a
-rwxr-xr-x.  1 root root     982 Jul 26 13:26 libevent_extra.la
lrwxrwxrwx.  1 root root      27 Jul 26 13:26 libevent_extra.so -> libevent_extra-2.0.so.5.0.1
-rwxr-xr-x.  1 root root     940 Jul 26 13:26 libevent.la
lrwxrwxrwx.  1 root root      29 Jul 26 13:26 libevent_openssl-2.0.so.5 -> libevent_openssl-2.0.so.5.0.1
-rwxr-xr-x.  1 root root  117392 Jul 26 13:26 libevent_openssl-2.0.so.5.0.1
-rw-r--r--.  1 root root  217556 Jul 26 13:26 libevent_openssl.a
-rwxr-xr-x.  1 root root    1011 Jul 26 13:26 libevent_openssl.la
lrwxrwxrwx.  1 root root      29 Jul 26 13:26 libevent_openssl.so -> libevent_openssl-2.0.so.5.0.1
lrwxrwxrwx.  1 root root      30 Jul 26 13:26 libevent_pthreads-2.0.so.5 -> libevent_pthreads-2.0.so.5.0.1
-rwxr-xr-x.  1 root root   26440 Jul 26 13:26 libevent_pthreads-2.0.so.5.0.1
-rw-r--r--.  1 root root   26454 Jul 26 13:26 libevent_pthreads.a
-rwxr-xr-x.  1 root root    1003 Jul 26 13:26 libevent_pthreads.la
lrwxrwxrwx.  1 root root      30 Jul 26 13:26 libevent_pthreads.so -> libevent_pthreads-2.0.so.5.0.1
lrwxrwxrwx.  1 root root      21 Jul 26 13:26 libevent.so -> libevent-2.0.so.5.0.1

二、安装jsoncpp

开源地址:https://github.com/open-source-parsers/jsoncpp

wget https://github.com/open-source-parsers/jsoncpp/archive/refs/tags/1.9.4.tar.gz
tar -zxvf 1.9.4.tar.gz
cd jsoncpp-1.9.4/
mkdir build && cd build/

cmake -DCMAKE_BUILD_TYPE=release \
-DBUILD_STATIC_LIBS=ON \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_INSTALL_INCLUDEDIR=/usr/include/jsoncpp \
-DARCHIVE_INSTALL_DIR=. -G "Unix Makefiles" ../

make -j2
sudo make install
[username@localhost build]$ sudo make install
[sudo] password for username:
Consolidate compiler generated dependencies of target jsoncpp_lib
[ 23%] Built target jsoncpp_lib
Consolidate compiler generated dependencies of target jsoncpp_static
[ 47%] Built target jsoncpp_static
Consolidate compiler generated dependencies of target jsoncpp_object
[ 64%] Built target jsoncpp_object
Consolidate compiler generated dependencies of target jsontestrunner_exe
[ 76%] Built target jsontestrunner_exe
Consolidate compiler generated dependencies of target jsoncpp_test
[100%] Built target jsoncpp_test
Install the project...
-- Install configuration: "release"
-- Installing: /usr/local/lib64/pkgconfig/jsoncpp.pc
-- Installing: /usr/local/lib64/cmake/jsoncpp/jsoncppConfig.cmake
-- Installing: /usr/local/lib64/cmake/jsoncpp/jsoncppConfig-release.cmake
-- Installing: /usr/local/lib64/cmake/jsoncpp/jsoncppConfigVersion.cmake
-- Installing: /usr/local/lib64/libjsoncpp.so.1.9.4
-- Installing: /usr/local/lib64/libjsoncpp.so.24
-- Installing: /usr/local/lib64/libjsoncpp.so
-- Installing: /usr/local/lib64/libjsoncpp_static.a
-- Installing: /usr/local/lib64/objects-release/jsoncpp_object/json_reader.cpp.o
-- Installing: /usr/local/lib64/objects-release/jsoncpp_object/json_value.cpp.o
-- Installing: /usr/local/lib64/objects-release/jsoncpp_object/json_writer.cpp.o
-- Installing: /usr/include/jsoncpp/json/allocator.h
-- Installing: /usr/include/jsoncpp/json/assertions.h
-- Installing: /usr/include/jsoncpp/json/config.h
-- Installing: /usr/include/jsoncpp/json/forwards.h
-- Installing: /usr/include/jsoncpp/json/json.h
-- Installing: /usr/include/jsoncpp/json/json_features.h
-- Installing: /usr/include/jsoncpp/json/reader.h
-- Installing: /usr/include/jsoncpp/json/value.h
-- Installing: /usr/include/jsoncpp/json/version.h
-- Installing: /usr/include/jsoncpp/json/writer.h

配置库目录
vim ~/.bashrc

export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH

source ~/.bashrc

三、http多线程服务

#pragma once

#include <event.h>
#include <evhttp.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <iostream>
#include <thread>
#include <vector>
#include <functional>
#include <list>

#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <cstdlib>
#include <jsoncpp/json/json.h>

using namespace std;

#define LOG_DBG   printf
#define LOG_INFO  printf
#define LOG_WARN  printf
#define LOG_ERR   printf


namespace servers
{
class HttpSrv
{
public:
	HttpSrv() {}
	~HttpSrv() {}
	bool start(int port, int nthreads);
	bool stop();

protected:
	struct WorkRoom {
		HttpSrv* pSrv;
		struct event_base* base;
		struct evhttp* httpd;
		struct event* watchdogEv;
		bool dispatchStop = false;
	};
	list<WorkRoom*> workRoomList;
	vector<thread> mWorkThList;

	bool mIsExit = false;

	static void watchdog(int fd, short event, void* argv);
	void Dispatch(void* arg);
	static void GenericHandler(struct evhttp_request* req, void* arg);
	static void ProcessRequest(struct evhttp_request* request, void* arg);
	static void HandlePostRequest(struct evhttp_request* request, void* arg);
	int BindSocket(int port);
};

int HttpSrv::BindSocket(int port)
{
	int r;
	int nfd;
	nfd = socket(AF_INET, SOCK_STREAM, 0);
	if (nfd < 0) return -1;

	int one = 1;
	r = setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(int));

	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;
	addr.sin_port = htons(port);

	r = bind(nfd, (struct sockaddr*)&addr, sizeof(addr));
	if (r < 0) return -1;
	r = listen(nfd, 10240);
	if (r < 0) return -1;

	int flags;
	if ((flags = fcntl(nfd, F_GETFL, 0)) < 0 || fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) return -1;
	return nfd;
}

bool HttpSrv::start(int port, int nthreads) {
	int r;
	int nfd = BindSocket(port);//监听端口
	if (nfd < 0) return false;
	for (int i = 0; i < nthreads; i++)
	{
		WorkRoom* w = new WorkRoom;//每个线程独有的环境参数,不使用局部变量,防止离开局部作用域后失效
		w->pSrv = this;

		w->base = event_init();    //libevnet使用多线程,每个线程中使用一个base
		if (w->base == NULL) return false;
		w->httpd = evhttp_new(w->base);//初始化http
		if (w->httpd == NULL) return false;
		r = evhttp_accept_socket(w->httpd, nfd);
		if (r != 0) return false;
		evhttp_set_gencb(w->httpd, GenericHandler, this);       //设置http路由 404
		evhttp_set_cb(w->httpd, "/test", ProcessRequest, this); //设置http路由
		evhttp_set_cb(w->httpd, "/image", HandlePostRequest, this); //设置http路由

		struct timeval tv;
		tv.tv_sec = 1;
		tv.tv_usec = 0;
		event* watchdogEv = event_new(w->base, -1, EV_PERSIST | EV_TIMEOUT, watchdog, w);//每个base设置一个看门狗,可以做一些线程监控的工作
		w->watchdogEv = watchdogEv;
		event_add(watchdogEv, &tv);

		mWorkThList.push_back(std::thread(std::bind(&HttpSrv::Dispatch, this, std::placeholders::_1), w)); //启动事件分发
		workRoomList.push_back(w);//线程环境变量收集,善后处理
	}
	LOG_INFO("http start port:%d, thNum:%d\n", port, nthreads);
	return true;
}

bool HttpSrv::stop() {
	mIsExit = true;

	while (workRoomList.size() > 0) {

		for (auto w : workRoomList) {
			if (!w->dispatchStop) {
				continue;
			}

			if (w->watchdogEv) {
				event_free(w->watchdogEv);
				w->watchdogEv = nullptr;
			}

			if (w->httpd) {
				evhttp_free(w->httpd);
				w->httpd = nullptr;
			}

			if (w->base) {
				event_base_free(w->base);
				w->base = nullptr;
			}

			workRoomList.remove(w);
			delete w;
			break;
		}
	}

	for (auto& t : mWorkThList) {
		if (t.joinable()) {
			t.join();
		}
	}

	return true;
}

void HttpSrv::Dispatch(void* arg) {
	LOG_DBG("dispatch start\n");
	WorkRoom* w = (WorkRoom*)arg;
	event_base_dispatch(w->base);
	LOG_DBG("dispatch stop\n");
	w->dispatchStop = true;
}

void HttpSrv::watchdog(int fd, short event, void* argv) {
	WorkRoom* w = (WorkRoom*)argv;
	HttpSrv* pSrv = w->pSrv;
	if (pSrv->mIsExit) {
		struct timeval delay = { 0, 1 };
		event_base_loopexit(w->base, &delay);
	}
}

void HttpSrv::GenericHandler(struct evhttp_request* req, void* arg)
{
	((HttpSrv*)arg)->ProcessRequest(req, arg);
}

void HttpSrv::ProcessRequest(struct evhttp_request* req, void* arg)
{
	// sleep(1);
	struct evbuffer* buf = evbuffer_new();
	if (buf == NULL)
		return;
	evbuffer_add_printf(buf, "Requested: %s\n", evhttp_request_uri(req));
	evhttp_send_reply(req, HTTP_OK, "OK", buf);
}

void HttpSrv::HandlePostRequest(struct evhttp_request* req, void* arg)
{
	// Get URI
	const char* uri = evhttp_request_uri(req);

	// Parse URI
	struct evkeyvalq params;
	evhttp_parse_query(uri, &params);

	// Get parameters
	const char* key = evhttp_find_header(&params, "key");
	const char* key2 = evhttp_find_header(&params, "key2");

	// Check if parameters are present
	if (key != NULL) {
		// Process key
		// ...
		return;
	}
	if (key2 != NULL) {
		// Process key2
		// ...
		return;
	}


	size_t len = evbuffer_get_length(req->input_buffer);
	char* data = (char*)malloc(len);
	evbuffer_remove(req->input_buffer, data, len);

	Json::Reader reader;
	Json::Value json;
	if (!reader.parse(data, json)) {
		// Handle error
		return;
	}

	// Process JSON data
	// ...

	// Create response
	Json::Value response;
	response["status"] = "success";
	Json::FastWriter writer;
	std::string output = writer.write(response);

	struct evbuffer* buf = evbuffer_new();
	evbuffer_add(buf, output.c_str(), output.size());
	evhttp_send_reply(req, HTTP_OK, "OK", buf);

	free(data);
}

}


int main()
{
	servers::HttpSrv s;
	s.start(8080, 5);

	sleep(60);

	LOG_INFO("http to stop\n");
	s.stop();
	LOG_INFO("http stop\n");

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
libevent是一个事件驱动的网络库,用于开发高效的网络应用程序。它支持多线程编程,但是在使用libevent多线程模式时需要注意一些问题。首先,libevent的信号事件是不支持多线程的,因为它使用了全局变量。这意味着在多线程环境下,注册信号事件可能会导致竞争条件和错误的结果。这一点可以在中的文章中找到更详细的解释。为了避免这个问题,可以考虑使用其他方式处理信号事件。 另外,在多线程模式下,主线程和工作线程之间可能存在并发操作事件的问题。当一个线程注册事件时,另一个线程可能同时在操作事件,比如删除或修改事件。libevent的源代码中没有提供同步保护机制,这可能导致严重的问题。因此,在多线程模式下使用libevent时,需要谨慎处理事件的操作,确保线程安全。这一点可以在中的文章中找到更详细的说明。 总结来说,libevent支持多线程编程,但需要注意信号事件不支持多线程,并且需要处理并发操作事件的问题。在使用libevent多线程模式时,建议仔细阅读相关文档和源代码,确保线程安全性。123 #### 引用[.reference_title] - *1* *2* [libevent多线程](https://blog.csdn.net/zhbt1234/article/details/53782589)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}} ] [.reference_item] - *3* [libevent学习笔记十三:让libevent支持多线程](https://blog.csdn.net/jyl_sh/article/details/105895355)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SongpingWang

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值