分享C++写的可嵌入应用程序的小型HTTP服务器

由于经常需要这样一些场合,让应用程序能够响应简单的HTTP请求,以实现一些功能,所以就做了一个这样的小型HTTP服务器库。库使用C++实现,编译成MT,Release模式的静态链接库,欢迎有兴趣的朋友使用。该库仅适用Windows操作系统。

下面是库的定义:

#ifndef __HOVERLEES_TINY_HTTPD_H
#define __HOVERLEES_TINY_HTTPD_H

#include <Windows.h>
#include <WinSock.h>
#include <map>

struct HoverCompare{
	bool operator()(const char* x, const char* y){
		return strcmp(x,y)<0;
	}
};
/**
 * @name 嵌入应用程序的简单HTTP服务器
 * @author Hoverlees http://www.hoverlees.com
 * 调用者继承这个类以处理HTTP请求
 */
class TinyHttpd{
private:
	static bool inited;
	static WSADATA wsaData;
	static DWORD WINAPI ServerThreadProc(void* lpParameter);
	static DWORD WINAPI ClientThreadProc(void* lpParameter);
protected:
	const static int STATUS_IDLE=0;
	const static int STATUS_RUNNING=1;
	typedef std::map<char*,char*,HoverCompare> hmap;
	int status;
	SOCKET serverSocket;
	sockaddr_in address;
public:
	TinyHttpd();
	/**
	 * 启动服务器
	 * @param bindPort 梆定的HTTP端口
	 * @param bindIP 梆定IP地址
	 * @return 成功状态
	 */
	bool startServer(unsigned short bindPor=80,const char* bindIP="0.0.0.0");
	/**
	 * 停止服务器
	 * @return 成功状态
	 */
	bool stopServer();
	/**
	 * 向客户端发送应答,每一个请求只能调用一次这个函数。
	 * @param clientSocket 客户端socket
	 * @param mem 应答的内容
	 * @param memSize 应答内容大小
	 * @param response_headers HTTP响应头,如果不设置,可以为NULL
	 * @return 操作结果
	 */
	bool sendResponse(SOCKET clientSocket,const char* mem,int memSize,hmap* response_headers);
	/**
	 * 回调方法,当服务器收到HTTP请求时,调用这个函数,注意TinyHttpd只支持GET请求
	 * @param clientSocket客户端socket,一般不直接操作,而是传入到sendResponse中。
	 * @param uri 请求uri,如客户端请求 /hoverlees?a=1&b=2 时,uri是 /hoverlees
	 * @param params 请求参数,这是HTTP get参数key=>value的map对象.如 params["a"]=1
	 * @return 如果用户处理了该请求,返回true,这时服务器响应200,如果没处理请求返回false ,服务器响应404
	 */
	virtual bool onHttpRequest(SOCKET clientSocket,const char* uri,hmap* params){return false;}
};

#endif

使用示例如下:

#include <iostream>
#include <cstdlib>
#include "TinyHttpd.h"
using namespace std;

#pragma comment(lib,"TinyHttpd.lib")

class MyHttpd:public TinyHttpd{
public:
	MyHttpd():TinyHttpd(){
	};
	virtual bool onHttpRequest(SOCKET clientSocket,const char* uri,hmap* params){
		void* mem;
		FILE* fp;
		hmap headers;
		int fsize;
		//可以先在这儿对uri指定的文件进行判断,如果文件存在,可以直接输出文件,这样就完全实现了一个静态网页的服务器。
		if(strcmp(uri,"/hoverlees")==0){
			if((*params)["hello"]){
				//如果设置了hello参数,如:http://localhost/hoverlees?hello=1
				this->sendResponse(clientSocket,"Hello World!",12,0);
			}
			else this->sendResponse(clientSocket,"Hoverlees",9,NULL);
		}
		else if(strcmp(uri,"/pic")==0){ //http://localhost/pic
			fp=fopen("./1.png","rb");
			fseek(fp,0,SEEK_END);
			fsize=ftell(fp);
			mem=malloc(fsize);
			fseek(fp,0,SEEK_SET);
			fread(mem,1,fsize,fp);
			fclose(fp);
			headers["Content-Type"]="image/png";
			this->sendResponse(clientSocket,(char*)mem,fsize,&headers);
			free(mem);
		}
		else if(strcmp(uri,"/")==0){
			char* html="<html><body><a href='/hoverlees'>hoverlees</a> <a href='/pic'>Picture</a></body></html>";
			this->sendResponse(clientSocket,html,strlen(html),NULL);
		}
		else return false;
		return true;
	}
};

int main(int argc,char* argv[]){
	//创建服务器
	MyHttpd* httpd=new MyHttpd();
	//启动服务器
	httpd->startServer(80);
	while(1){
		Sleep(10000);
	}
	return 0;
}

相关的库文件和头文件在这里下载.test_app

Leave a comment

Your email address will not be published. Required fields are marked *