mongoose实现httpserver,client

使用mongoose来做http协议的基础,基本上的函数都在一个c文件里面,直接包含c文件就可以实现一个httpserve和httpclient,可以实现一个小型的httpserver,要求的并发数不是很高,如下所示,直接将mongoose.c包含在项目里面。

mongoose实现httpserver,client_第1张图片

1 server

首先http server 是一个线程类, 定义一个线程基类,然后httpserver从基类继承下去,使用start函数以后,线程开启,调用run函数,无限循环。server不仅是可以是httpserver,也可以是websocketserver。

/*
Author:钱波
email: [email protected]
wei:   18091589062
func  :线程类
time:  2018年5月30日
*/

#ifndef _TTHREAD_RUN_ABLE_H_
#define _TTHREAD_RUN_ABLE_H_
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

class TThreadRunable
{
private:

	//线程
	thread _thread;
	//等待信号
	std::mutex _signal_mutex;
	std::condition_variable _cond;
protected:
	//char  _running = false;
	char _stop = true;
	//锁定运行状态
	std::mutex _mutex;
public:
	TThreadRunable()
	{}
	virtual ~TThreadRunable()
	{}

public:
	char * status(){
		return &_stop;
	}
	
	void Join()
	{
		if (_thread.joinable())
			_thread.join();
	}
	bool  IsStop()
	{
		return _stop == 1 ? true : false;
	}

	void WaitForSignal()
	{
		std::unique_lock<std::mutex> ul(_signal_mutex);
		_cond.wait(ul);
	}
	void Notify()
	{
		_cond.notify_one();
	}

	virtual int Start()
	{
		if (_stop == 1)//非運行中
		{
			_stop = 0;
			_thread = std::thread(std::bind(&TThreadRunable::Run, this));
			return 0;
		}
		return -1;
	}	
	
	virtual void Stop()
	{
		_stop = 1; // true;
	}

	virtual void Run() = 0;
};
#endif

实现httpserver,主要是实现httpserver的run函数,实现循环。

#include "mongoose.h"
#include "TThreadRunable.h"
#include 
#include 
#include 
using namespace std;
//typedef struct re_param
//{
//	void * pUser;
//	string uri;
//	string host;
//	string uid;
//	string message;
//}re_param;
//using handler = std::function ;
typedef struct request_param
{
	//返回的
	string retString;
	map<string, string> params;
	void insertParam(string key)
	{
		params[key] = "null";
	}
	void setParam(string key, string value)
	{
		params[key] = value;
	}
	const char* getParam(string key)
	{
		if (params.find(key) != params.end())
		{
			return params[key].c_str();
		}
		return NULL;
	}
	int getSize()
	{
		return (int)params.size();
	}
	map<string, string>::iterator iter;
	const char * GetFirstParam()
	{
		iter = params.begin();
		if (iter == params.end())
			return NULL;
		return iter->first.c_str();
	}
	void SetParamValue(const char *value)
	{
		if (iter != params.end())
			iter->second = value;
	}

	const char * GetNextParam()
	{
		iter++;
		if (iter == params.end())
		{
			return NULL;
		}
		else
		{
			return iter->first.c_str();
		}
	}
}request_param;

using handler2 = std::function<void(request_param &rp)>;

typedef struct route_request
{
	request_param _param;
	handler2 func;
}route_request;


class Service_HTTP :public TThreadRunable
{
protected:
	using handler_map = std::map<std::string, route_request>;
	handler_map _handlers;
public:
	//handler handlestart = nullptr;
	//handler handlestop  = nullptr;
	//handler hanlde_volume = nullptr;
	//handler handle_microphone = nullptr;
	handler_map &GetHandleMap()
	{
		return _handlers;
	}

	const char *s_http_port = "9091";
	struct mg_serve_http_opts _s_http_server_opts;
	struct mg_mgr _mgr;
	struct mg_connection * _nc = NULL;

	bool RegisterHandler(std::string uri, route_request f) {
		auto it = _handlers.find(uri);
		if (_handlers.end() != it)
			return false;

		return _handlers.emplace(uri, f).second;
	}


	void UnRegisterHandler(std::string uri) {
		auto it = _handlers.find(uri);
		if (_handlers.end() != it)
			_handlers.erase(it);
	}

public:

	//static void handle_api(string uri, struct mg_connection *nc, struct http_message *hm);
	static void handle_api2(string uri, struct mg_connection *nc, struct http_message *hm);

	static void ev_handler(struct mg_connection *nc, int ev, void *ev_data);
	static int is_websocket(const struct mg_connection *nc) {
		return nc->flags & MG_F_IS_WEBSOCKET;
	}

	
//广播该视频数据
	void WebSocket_Broadcast(void * s2);
	//void WebSocket_Broadcast1(void * pUser, uint8_t * data, int len);
public:
	~Service_HTTP()
	{
	}
	void Stop();
	void Run();
	

};

下面是实现文件

#include "restful_server.h"



//#include "../CorePhone/TPictureInfo.h"


static struct mg_serve_http_opts s_http_server_opts;


void Service_HTTP::WebSocket_Broadcast(void *s)
{
	//return ;
	//int jpglen = 0;
	//videosend2 *s2 = (videosend2 *)s;
	//char * jpg = NULL;
	//plus.EncodeRGB2Jpeg((char*)s2->data, s2->w, s2->h, (s2->w)*3, &jpg, jpglen);
	//struct mg_connection *c;
	//if (_nc != NULL) {
	//	for (c = mg_next(_nc->mgr, NULL); c != NULL; c = mg_next(_nc->mgr, c)) {
	//		if (c == _nc) continue; /* Don't send to the sender. */
	//		mg_send_websocket_frame(c, WEBSOCKET_OP_BINARY, jpg, jpglen);
	//	}
	//}
	//if (jpg != NULL)
	//	delete[]jpg;
}

//void Service_HTTP::WebSocket_Broadcast1(void * pUser, uint8_t * data, int len)
//{
//	struct mg_connection *c;
//	if (pUser == NULL)
//		return;
//
//	if (_nc != NULL) {
//		for (c = mg_next(_nc->mgr, NULL); c != NULL; c = mg_next(_nc->mgr, c)) {
//			if (c == pUser)
//				mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, data, len);
//		}
//	}
//
//}


void Service_HTTP::handle_api2(string uri, struct mg_connection *nc, struct http_message *hm)
{
	Service_HTTP *sh = (Service_HTTP*)nc->user_data;
	if (sh == NULL)
		return;
	handler_map& hmap = sh->GetHandleMap();
	handler_map::iterator iter;
	iter = hmap.find(uri);
	if (iter == hmap.end())
	{
		mg_serve_http(nc, hm, s_http_server_opts); /* Serve static content */
		return;
	}
	route_request & rr = iter->second;
	const char * param = rr._param.GetFirstParam();
	while (param != NULL)
	{
		char buffer[255];
		mg_get_http_var(&hm->query_string, param, buffer, sizeof(buffer));
		rr._param.SetParamValue(&buffer[0]);
		//rr._param.setParam(string(param), string(buffer));
		param = rr._param.GetNextParam();
	}
	

	/* Send headers */
	//mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n");
	mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *");
	//允许哪些url可以跨域请求到本域
	//mg_printf(nc, "Access-Control-Allow-Origin:*\r\n");
	//允许的请求方法,一般是GET,POST,PUT,DELETE,OPTIONS
	mg_printf(nc, "Access-Control-Allow-Methods:POST,OPTIONS,GET\r\n");
	//允许哪些请求头可以跨域
	mg_printf(nc, "Access-Control-Allow-Headers:x-requested-with,content-type\r\n");
	if (rr.func != nullptr)
	{
		rr.func(rr._param);
	}

	string	reply = "{\"ret\":0}";
	if(!rr._param.retString.empty())
		reply = rr._param.retString;
	mg_printf(nc, "Content-Type:application/json\r\n");
	mg_printf(nc, "Content-Length:%u\r\n\r\n%s\r\n", (uint32_t)reply.size(), reply.c_str());
	//mg_printf(nc, "HTTP/1.1 200 OK\r\niConnection: close\r\nContent-Type: text/html\r\nContent-Length: %u\r\n\r\n%s\r\n",
	nc->flags |= MG_F_SEND_AND_CLOSE;
	//mg_send(nc, "", 0);
}
#if 0
void Service_HTTP::handle_api(string uri, struct mg_connection *nc, struct http_message *hm)
{
	Service_HTTP *sh = (Service_HTTP*)nc->user_data;
	if (sh == NULL)
		return;

	//const char * param = sh->_param.GetFirstParam();
	if (uri.compare("/start") == 0)
	{
		char host[64];
		char uid[64];
		char message[64];
		mg_get_http_var(&hm->query_string, "serverhost", host, sizeof(host));
		mg_get_http_var(&hm->query_string, "uid", uid, sizeof(uid));
		mg_get_http_var(&hm->query_string, "message", message, sizeof(message));
		/* Send headers */
		//mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n");
		mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *");
		//允许哪些url可以跨域请求到本域
		mg_printf(nc, "Access-Control-Allow-Origin:*\r\n");
		//允许的请求方法,一般是GET,POST,PUT,DELETE,OPTIONS
		mg_printf(nc, "Access-Control-Allow-Methods:POST\r\n");
		//允许哪些请求头可以跨域
		mg_printf(nc, "Access-Control-Allow-Headers:x-requested-with,content-type\r\n");
		string reply = "{\"result\":0}";
		mg_printf(nc, "Content-Length:%u\r\n\r\n%s\r\n", (uint32_t)reply.size(), reply.c_str());
		//mg_printf(nc, "HTTP/1.1 200 OK\r\niConnection: close\r\nContent-Type: text/html\r\nContent-Length: %u\r\n\r\n%s\r\n",
		nc->flags |= MG_F_SEND_AND_CLOSE;
		mg_send(nc, "", 0);
		//mg_printf_http_chunk(nc, "{ \"result\": %ld }", 0);
		//mg_send_http_chunk(nc, "", 0); /* Send empty chunk, the end of response */

		
		re_param request;
		request.uri = uri;
		request.pUser = NULL;
		request.host = host;
		request.uid = uid;
		request.message = message;
		if (sh->handlestart != nullptr)
			sh->handlestart(request);
		//it->second(request);
		OutputDebugString(L"start video to");
		//callback(__void, host, uid, message);
		
	}
	else if (uri.compare("/stop") == 0) //停止
	{
		char message[64];

		mg_get_http_var(&hm->query_string, "message", message, sizeof(message));
		/* Send headers */
		//mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n");
		mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *");
		//允许哪些url可以跨域请求到本域
		mg_printf(nc, "Access-Control-Allow-Origin:*\r\n");
		//允许的请求方法,一般是GET,POST,PUT,DELETE,OPTIONS
		mg_printf(nc, "Access-Control-Allow-Methods:POST\r\n");
		//允许哪些请求头可以跨域
		mg_printf(nc, "Access-Control-Allow-Headers:x-requested-with,content-type\r\n");
		string reply = "{\"result\":0}";
		mg_printf(nc, "Content-Length:%u\r\n\r\n%s\r\n", (uint32_t)reply.size(), reply.c_str());
		//mg_printf(nc, "HTTP/1.1 200 OK\r\niConnection: close\r\nContent-Type: text/html\r\nContent-Length: %u\r\n\r\n%s\r\n",
		nc->flags |= MG_F_SEND_AND_CLOSE;

		mg_send(nc, "", 0);
		//mg_printf(nc, "{ \"result\": %ld }", 0);
		//mg_send(nc, "", 0);
		//mg_printf_http_chunk(nc, "{ \"result\": %ld }", 0);
		//mg_send_http_chunk(nc, "", 0); /* Send empty chunk, the end of response */

		
			//auto it = sh->GetHandleMap().find(uri);
			//if (sh->GetHandleMap().end() == it)
			//	return;
			re_param request;
			request.uri = uri;
			request.pUser = NULL;
			request.message = message;
			if(sh->handlestop!=nullptr)
				sh->handlestop(request);
			OutputDebugString(L"stop video");
	}
	//else if(uri.compare("getmicrophone"))
	//获取
}
#endif



void Service_HTTP::ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
	struct http_message *hm = (struct http_message *) ev_data;
	//传送文件地址和转化的目的地址
	//   /api/t2pdf
	switch (ev) {

	case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
		printf("here connection\n");
		break;
	case MG_EV_WEBSOCKET_FRAME: {
		struct websocket_message *wm = (struct websocket_message *) ev_data;
		/* New websocket message. Tell everybody. */
		struct mg_str d = { (char *)wm->data, wm->size };
		
		//broadcast(nc, d);
		break;
	}

	case MG_EV_HTTP_REQUEST:
	{
		string uri = string(hm->uri.p, hm->uri.len);
		handle_api2(uri, nc, hm);
		//if (mg_vcmp(&hm->uri, "/start") == 0) {
		//	handle_api2(uri, nc, hm);
		//}
		//else if (mg_vcmp(&hm->uri, "/stop") == 0) {
		//	handle_api2(uri, nc, hm);
		//}
		//else
		//{
		//	mg_serve_http(nc, hm, s_http_server_opts); /* Serve static content */
		//}
		break;
	}
	case MG_EV_CLOSE:
	{
		if (is_websocket(nc))
			OutputDebugString(L"websocket out");
		break;
	}
	default:
		break;
	}
}


void Service_HTTP::Stop()
{
	TThreadRunable::Stop();
	Join();
}



void Service_HTTP::Run()
{
	mg_mgr_init(&_mgr, NULL);
	_nc = mg_bind(&_mgr, s_http_port, ev_handler);
	_nc->user_data = this;
	mg_set_protocol_http_websocket(_nc);
	s_http_server_opts.document_root = "./public";  // Serve current directory
	s_http_server_opts.enable_directory_listing = "yes";
	//printf("Started on port %s\n", s_http_port);
	while (!IsStop()) {
		mg_mgr_poll(&_mgr, 50);
	}
	mg_mgr_free(&_mgr);

}

run函数是一个无线while循环,注意mongoose谈不上有太高的效率,实际上就是使用mg_mgr_poll来实现的,每隔50毫秒刷新一次,这个50毫秒可以自行修改。
调用的时候也可以使用lamba函数,如下所示

handler hd1 = std::bind(&CMeetingDlg::StartHttpCallback, this, std::placeholders::_1);
_httpserver.RegisterHandler("/start", hd1);

下面实现client

#pragma once
#include 
#include 


#include "mongoose.h"
#include "../CorePhone/TThreadRunable.h"

typedef void(*callback_http)(std::string);
class HttpClient//:public TThreadRunable
{
private:
	mg_connection *connection = NULL;
	mg_mgr mgr;
	std::string _posturl;
public:
	void seturl(const char * ip)
	{
		//string temp = url;
		_posturl = "http://";
		_posturl += ip;
		_posturl += "/streamclose";
	}
public:
	HttpClient();
	~HttpClient();

	void SendReq();
	static void OnHttpEvent(mg_connection *connection, int event_type, void *event_data);
	int s_exit_flag;
	callback_http s_callback;
	//void Run();
};
#include "HttpClient.h"

//ReqCallback HttpClient::s_req_callback;

// 客户端的网络请求响应
void HttpClient::OnHttpEvent(mg_connection *connection, int event_type, void *event_data)
{
	HttpClient * hc =(HttpClient *)connection->user_data;
	http_message *hm = (struct http_message *)event_data;
	int connect_status;

	switch (event_type)
	{
	case MG_EV_CONNECT:
		connect_status = *(int *)event_data;
		if (connect_status != 0)
		{
			printf("Error connecting to server, error code: %d\n", connect_status);
			hc->s_exit_flag = 1;
		}
		break;
	case MG_EV_HTTP_REPLY:
	{
		printf("Got reply:\n%.*s\n", (int)hm->body.len, hm->body.p);
		std::string rsp = std::string(hm->body.p, hm->body.len);
		connection->flags |= MG_F_SEND_AND_CLOSE;
		hc->s_exit_flag = 1; // 每次收到请求后关闭本次连接,重置标记

		// 回调处理
		hc->s_callback(rsp);
	}
	break;
	case MG_EV_CLOSE:
		if (hc->s_exit_flag == 0)
		{
			printf("Server closed connection\n");
			hc->s_exit_flag = 1;
		};
		break;
	default:
		break;
	}
}


// 发送一次请求,并回调处理,然后关闭本次连接
void HttpClient::SendReq()
{
	if (_posturl.empty())
		return;


	// 给回调函数赋值
	//s_callback = req_callback;

	connection = mg_connect_http(&mgr, OnHttpEvent, _posturl.c_str(), NULL, NULL);
	connection->user_data = this;
	mg_set_protocol_http_websocket(connection);

	//printf("Send http request %s\n", _posturl.c_str());

	// loop
	//while (s_exit_flag == 0)
	mg_mgr_poll(&mgr, 50);
	mg_mgr_poll(&mgr, 50);


}
HttpClient::HttpClient()
{
	mg_mgr_init(&mgr, NULL);
}
HttpClient::~HttpClient()
{
	mg_mgr_free(&mgr);
}
//void HttpClient::Run()
//{
//
//}

简单的server和client 就可以这么简单的实现,不用花费太多精力。

你可能感兴趣的:(c++,websocket,协议,http协议,c++,开发语言,httpserver,httpclient)