mongoose实现httpserver,client

Posted qianbo_insist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mongoose实现httpserver,client相关的知识,希望对你有一定的参考价值。

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

1 server

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

/*
Author:钱波
email: 418511899@qq.com
wei:   18091589062
func  :线程类
time:  2018年5月30日
*/

#ifndef _TTHREAD_RUN_ABLE_H_
#define _TTHREAD_RUN_ABLE_H_
#include <mutex>
#include <queue>
#include <thread>
#include <atomic>
#include <condition_variable>
#include <functional>
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 <string>
#include <functional>
#include <map>
using namespace std;
//typedef struct re_param
//
//	void * pUser;
//	string uri;
//	string host;
//	string uid;
//	string message;
//re_param;
//using handler = std::function <void(re_param &param)>;
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(&_mg

以上是关于mongoose实现httpserver,client的主要内容,如果未能解决你的问题,请参考以下文章

HttpServer和HttpsServer简单实现

httpserver实现简单的上下文

自主HttpServer实现(C++实战项目)

Go语言HTTPServer开发的六种实现

基于Netty4的HttpServer和HttpClient的简单实现

使用Java实现简单的Http服务器