c++使用libevent寫的httpserver

直接上代碼:測試過可用。需要下載libevent庫搭配着使用。外加json開源庫(也可以不用,去掉相關代碼即可。)


// .h
#pragma once

class HttpServer
{
public:
	HttpServer();
	~HttpServer();

	static HttpServer* Instance(){ return m_instance; }

	void StartListen(int httpPort); // 監聽端口

private:
	int httpserver_bindsocket(int port, int backlog);
	void* httpserver_Dispatch(void *arg);	

	bool Linsten(int httpPort);
private:

	static HttpServer* m_instance;
	class AutoDel
	{
	public:
		~AutoDel()
		{
			if (m_instance != nullptr)
			{
				delete m_instance;
				m_instance = nullptr;
			}
		}
	};
	static AutoDel m_del;
};


//.cpp  

#include <time.h>
#include <thread>
#include <Winsock2.h>
#include "event2/event.h"
#include "event2/buffer.h"
#include "event2/http.h"
#include "evhttp.h"
#include "json\include\reader.h"
#include "json\include\writer.h"
#include "HttpServer.h"


// libevent庫需要用到
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"AdvAPI32.lib")
#pragma comment(lib,"wsock32.lib")

bool GetRequest(struct evhttp_request *req, std::string &requestStr)
{
	//WLog(LOG_DEBUG, "GetRequest threadId[%d] remoteHost[%s][%d]", std::this_thread::get_id(),req->remote_host, req->remote_port);
	size_t postSize = EVBUFFER_LENGTH(req->input_buffer);
	char *postData = (char *)EVBUFFER_DATA(req->input_buffer);
	if (postSize > 0)
	{
		requestStr = std::string(postData, postSize);
		return true;
	}

	requestStr = "data is null";
	return false;
}

void Response(struct evhttp_request *req, const std::string &replyStr)
{
	evbuffer *buff = evbuffer_new();
	evbuffer_add_printf(buff, "%s", replyStr.c_str());
	evhttp_send_reply(req, HTTP_OK, "OK", buff);
	evbuffer_free(buff);
}

void RegistImage(struct evhttp_request *req, void *arg)
{
	std::string requestStr, responseStr;
	bool bsucc = false;
	do
	{
		bsucc = GetRequest(req, requestStr);
		if (bsucc)
		{
			Json::Reader reader;
			Json::Value val;
			bsucc = reader.parse(requestStr, val);
			if (!bsucc)
			{
				//WLog(LOG_ERR, "regist fail, parse requestStr[%s] err", requestStr.c_str());
				responseStr = "regist fail, parse requestStr err";
				break;
			}

			std::string id = val["uid"].asString();
			std::string name = val["name1"].asString();
			std::string imgstr = val["image"].asString();
			responseStr = "succ";
			
		}
	} while (0);

	Json::FastWriter wr;
	Json::Value wrVal;
	wrVal["code"] = bsucc ? "0" : "-1";
	wrVal["msg"] = bsucc ? "OK" : responseStr;

	Response(req, wr.write(wrVal));
}

//--------------------http服務器類--------------------

HttpServer* HttpServer::m_instance = new HttpServer;
HttpServer::HttpServer()
{
	// windows下必須使用此來初始化套接字
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
}


HttpServer::~HttpServer()
{
	// 程序最後調用WSACleanup();釋放資源
	WSACleanup();
}

void HttpServer::StartListen(int httpPort)
{
	std::thread t(&HttpServer::Linsten, this, httpPort);
	t.detach();
}

bool HttpServer::Linsten(int httpPort)
{
	int r, i;
	int nfd = httpserver_bindsocket(httpPort, 10000);
	if (nfd < 0)
	{
		return false;
	}

	std::vector<std::thread> threadVec;
	for (i = 0; i < 20; i++)
	{
		struct event_base *base = event_base_new();
		if (base == NULL)
		{
			continue;
		}
		struct evhttp *httpd = evhttp_new(base);
		if (httpd == NULL)
		{
			event_base_free(base);
			continue;
		}

		r = evhttp_accept_socket(httpd, nfd);
		if (r != 0)
		{
			evhttp_free(httpd);
			event_base_free(base);
			continue;
		}
		evhttp_set_timeout(httpd, 10);
		evhttp_set_cb(httpd, "/v1/face/register", RegistImage, NULL);  
		//evhttp_set_gencb(httpd, generic_handler, NULL);
		threadVec.push_back(std::thread(&HttpServer::httpserver_Dispatch, this, base));
	}
	//WLog(LOG_INFO, "http server start at port:%d", httpPort);

	for (i = 0; i < threadVec.size(); i++)
	{
		threadVec[i].join();
	}
	return true;
}

int HttpServer::httpserver_bindsocket(int port, int backlog) 
{
	int r;
	int nfd;
	nfd = socket(AF_INET, SOCK_STREAM, 0);
	if (nfd < 0)
	{
		//WLog(LOG_ERR, "socket port[%d] ret[%d] err[%d]",port, nfd,GetLastError());
		return nfd;
	}
	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)
	{
		//WLog(LOG_ERR, "bind port[%d] ret[%d],err[%d]", port, r, WSAGetLastError());
		return r;
	}
	r = listen(nfd, backlog);
	if (r < 0)
	{
		//WLog(LOG_ERR, "listen port[%d] ret[%d],err[%d]", port, r, GetLastError());
		return r;
	}

	//設置非阻塞
	unsigned long flags = 1;
	if (ioctlsocket(nfd, FIONBIO, &flags) < 0)
		return -1;

	return nfd;
}

void* HttpServer::httpserver_Dispatch(void *arg)
{
	event_base_dispatch((struct event_base*)arg);
	return NULL;
}

void* HttpServer::httpserver_Dispatch(void *arg)
{
	event_base_dispatch((struct event_base*)arg);
	return NULL;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章