注意:這里是使用mongoose實現HTTP服務,非數據庫使用。
最近由於需要使用HTTP服務端,原先是使用的Qt框架實現的HTTP服務端,然后發現有些缺陷導致我不得不放棄這個框架,也不是完全放棄,只是HTTP服務端這里不再使用Qt,用Qt做高並發真的有點不好。
然后毅然的選擇了mongoose這個框架,主要是聽說這玩意 嵌入到代碼中非常方便。下載之后發現果然就一個 h文件和cpp文件。。
於是開始研究這個框架,根據mongoose 用戶手冊再加上一堆實例教程,基本上寫了一個類 進行操作封裝(並不是完全的封裝了)
MoHttp.h文件
主要是實現mongoose框架的基本 變量獲取。注意里面有重載,主要是為了方便使用。
#define _MOHTTP_H
#ifdef _MOHTTP_H
#include "mongoose.h"
#include <iostream>
using namespace std;
const int CHAR_HTTP_VAR_MAX = 128;
const int CHAR_HTTP_COOKIE_MAX = 400;
class MoHttp
{
private:
struct http_message *hm = NULL;
public:
MoHttp(struct http_message *);
~MoHttp();
int getGetVar(const char*, char*) const; //獲取變量
void getGetVar(const char*, string &) const; //獲取變量
int getPostVar(const char*, char*) const; //獲取變量
void getPostVar(const char*, string &) const; //獲取變量
int getCookie(const char*, char*) const; //獲取Cookie
void getCookie(const char*, string &) const; //獲取Cookie
int Model() const; //判斷當前模式 POST/GET 1為 GET 否則為0
};
#endif
MoHttp.cpp
實現各類方法。
#include "MoHttp.h"
MoHttp::MoHttp(struct http_message * hm = NULL)
{
this->hm = hm;
}
int MoHttp::getGetVar(const char* name, char* var) const
{
memset(var, '\0', sizeof(var));
if (hm == NULL || name == NULL || hm->query_string.p == NULL)return -1;
return mg_get_http_var(&hm->query_string, name, var, sizeof(var)); //獲取變量
}
void MoHttp::getGetVar(const char* name, string & str) const
{
str = "";
char var[CHAR_HTTP_VAR_MAX];
var[0] = '\0';
if (hm == NULL || name == NULL || hm->query_string.p == NULL)return;
mg_get_http_var(&hm->query_string, name, var, sizeof(var)); //獲取變量
if (var[0] == '\0'){
return;
}
str = var; //如果數據正確
}
int MoHttp::getPostVar(const char* name, char* var) const
{
memset(var,'\0',sizeof(var));
if (hm == NULL || name == NULL || hm->body.p == NULL)return -1;
return mg_get_http_var(&hm->body, name, var, sizeof(var)); //獲取變量
}
void MoHttp::getPostVar(const char* name, string & str) const
{
str = "";
char var[CHAR_HTTP_VAR_MAX];
var[0] = '\0';
if (hm == NULL || name == NULL || hm->query_string.p == NULL)return;
mg_get_http_var(&hm->body, name, var, sizeof(var)); //獲取變量
if (var[0] == '\0'){
return;
}
str = var; //如果數據正確
}
int MoHttp::Model() const
{
if (hm == NULL || hm->method.p == NULL)return -1; //數據錯誤
if (mg_vcmp(&hm->method, "POST") != 0)return 1;
return 0;
}
int MoHttp::getCookie(const char * name, char * var) const
{
memset(var, '\0', sizeof(var));
//mg_printf(nc, "Set-Cookie: %s=%s; path=/\r\n", "wwe", "123456789"); 發送Cookie
if (hm == NULL) return -999;
struct mg_str *cookie_header = mg_get_http_header(hm, "cookie"); //獲取Cookie 整條
if (cookie_header == NULL) return -999; //<0
return mg_http_parse_header(cookie_header, name, var, sizeof(var));
}
void MoHttp::getCookie(const char* name, string & str) const
{
str = "";
char var[CHAR_HTTP_COOKIE_MAX]; //Cookie 最大更長
var[0] = '\0';
if (hm == NULL || name == NULL || hm->query_string.p == NULL)return;
struct mg_str *cookie_header = mg_get_http_header(hm, "cookie"); //獲取Cookie 整條
if (cookie_header == NULL) return;
mg_http_parse_header(cookie_header, name, var, sizeof(var));
if (var[0] == '\0'){
return;
}
str = var; //如果數據正確
}
MoHttp::~MoHttp()
{
}
使用方法:
Mo.cpp(或Main.cpp)
// Copyright (c) 2016 by Suwings
// All rights reserved
#include <iostream>
#include "MoHttp.h"
using namespace std;
static char *s_http_port = "23333";
static struct mg_serve_http_opts s_http_server_opts;
MoHttp * mo = NULL;
static void ev_handler(struct mg_connection *nc, int ev, void *p) {
if (ev == MG_EV_HTTP_REQUEST) { //如果是HTTP 請求
struct http_message *hm = (struct http_message *) p; //傳為
mo = new MoHttp(hm); //記得釋放內存,實例化 MoHttp
if (mo->Model()==1){
//GET
string w; //測試代碼
mo->getGetVar("user",w); //測試代碼
if (w != "")cout << "變量:" << w.c_str() << endl; //測試代碼
}else{ //測試代碼
//POST
} //測試代碼
delete mo; //釋放變量
mg_serve_http(nc, hm, s_http_server_opts); //數據發送
}
}
int main(void) {
struct mg_mgr mgr;
struct mg_connection *nc;
//struct mg_request_info *ww;
mg_mgr_init(&mgr, NULL);
printf("[狀態] 服務器已經開啟在端口: %s\n", s_http_port);
nc = mg_bind(&mgr, s_http_port, ev_handler);
if (nc == NULL) {
printf("Failed to create listener\n");
return 1;
}
// Set up HTTP server parameters
mg_set_protocol_http_websocket(nc);
s_http_server_opts.document_root = "./www/"; // Serve current directory
s_http_server_opts.enable_directory_listing = "no"; //Set if show dir
for (;;) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
return 0;
}
看了幾個小時之后,差不多只能寫出這么點東西了。然后我就一直在想。
但是你有沒有發現,如果瀏覽器要是發送 Ajax 數據過來,假定邏輯在 C++ 代碼里面,我應該如何設置返回的數據啊?
的確,這個類也沒有加入 返回的數據,這個問題我也一直在困擾。
難道mongoose 框架都沒有函數是可以設置數據在 body 的?百思不得其解的我於是去找了一下 mongoose 文檔里面的例子,發現了一個Cookie驗證的例子,原本我以為不管怎么樣也會有設置數據的地方了,但是我驚奇的發現,是這樣的:
Cookie_auth.c 例子文件
static void set_session_cookie(struct mg_connection *nc,
const struct session *s) {
mg_printf(nc, "Set-Cookie: %s=%" INT64_X_FMT "; path=/\r\n",
SESSION_COOKIE_NAME, s->id);
}
/*
* If requested via GET, serves the login page.
* If requested via POST (form submission), checks password and logs user in.
*/
static void login_handler(struct mg_connection *nc, int ev, void *p) { //主要看這個函數
struct http_message *hm = (struct http_message *) p;
if (mg_vcmp(&hm->method, "POST") != 0) {
/* Serve login.html */
mg_serve_http(nc, (struct http_message *) p, s_http_server_opts);
} else {
/* Perform password check. */
char user[50], pass[50];
int ul = mg_get_http_var(&hm->body, "user", user, sizeof(user));
int pl = mg_get_http_var(&hm->body, "pass", pass, sizeof(pass));
if (ul > 0 && pl > 0) { //如果有數據
if (check_pass(user, pass)) { //驗證賬號和密碼 函數無須理會
struct session *s = create_session(user, hm); //mg_printf 是直接輸出數據,並不是輸出到body
mg_printf(nc, "HTTP/1.0 302 Found\r\n");
set_session_cookie(nc, s); //他是進行了一次跳轉,並且直接返回的HTTP頭
mg_printf(nc, "Location: /\r\n");
mg_printf(nc, "\r\nHello, %s!\r\n", s->user);
//這句是控制台輸出
fprintf(stderr, "%s logged in, sid %" INT64_X_FMT "\n", s->user, s->id);
} else {
mg_printf(nc, "HTTP/1.0 403 Unauthorized\r\n\r\nWrong password.\r\n");
}
} else {
mg_printf(nc, "HTTP/1.0 400 Bad Request\r\n\r\nuser, pass required.\r\n");
}
nc->flags |= MG_F_SEND_AND_CLOSE;
}
(void) ev;
}
看完了之后我就跟納悶了,為什么要直接輸出HTTP頭?框架難道真的沒有提供類似的方法嗎?
然后嘗試了各類函數:
也無果,這些函數會 輸出到 HTTP 響應頭之前。

所以,是不是這個框架真的沒有 什么設置返回的body 的函數呢?
總之目前只學到這里,也許有什么地方確實沒有了解。暫且先記錄下來,等知道了之后再續寫。

