基于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");

}

猜你喜欢

转载自blog.csdn.net/wsp_1138886114/article/details/131962205