Windows提供的winhttp函数库用来快速实现HTTP协议的应用程序,包括客户端和服务器端。

服务器开发一般流程是这样的:

1.HttpInitialize 初始化WinHTTP函数库;

2.HttpCreateHttpHandle 创建一个HTTP队列句柄,用来接收HTTP请求;

3.HttpAddUrl 绑定要监听的URL,写为http://*:80/表示所有网卡80端口的HTTP请求都处理,其中的*号可以改为IP地址;

4.创建一个线程用来处理HTTP请求队列;

5.HttpReceiveHttpRequest 在线程中调用此函数,接收HTTP请求,在返回的PHTTP_REQUEST结构中有我们想要的各种数据;

6.HttpReceiveRequestEntityBody 这个函数用来接收HTTP请求的BODY部分,如果数据很长需要多次调用;

7.HttpSendHttpResponse 这个函数返回响应请求的数据,可以自行设置Header和Body;

8.要结束HTTP服务器,调用CloseHandle关闭HttpCreateHttpHandle返回的队列句柄;再调用HttpTerminate清理WinHTTP函数库;


下面的代码实现了一个最简单的HTTP服务器程序,仅供参考。

用法:

1. 创建IHttpServiceListener的派生类,实现该虚基类的OnRecvRequest函数,该函数是用于收到客户端请求时的回调函数。在回调函数中处理请求数据,如果要读取客户端POST的数据,则调用inst->RecvRequestBody;最后调用inst->SendRequestResp返回响应数据。

2.创建CHttpService类的实例,调用Create函数,提供监听端口和回调接口。


头文件:HttpService.h

#pragma once
#include <http.h>class CHttpService;class IHttpServiceListener
{
public:virtual BOOL OnRecvRequest(CHttpService *inst, PHTTP_REQUEST request)=0;
};class CHttpService
{
public:CHttpService();BOOL Create(INT port, IHttpServiceListener *listener);BOOL Delete(void);BOOL SendRequestResp(HTTP_REQUEST_ID req_id, INT status, LPCSTR reason, LPCSTR type, HANDLE file, LPVOID mem, DWORD mem_size);BOOL RecvRequestBody(HTTP_REQUEST_ID req_id, HANDLE file, char *mem, DWORD mem_size);BOOL DoReceiveRequests();BOOL GetRemoteAddr(PHTTP_REQUEST request, CString &text);
public:static UINT AFX_CDECL RecvRequestThread(LPVOID param);
private:HANDLE m_req_queue;LPBYTE m_req_buffer;UINT   m_req_buffer_size;CWinThread *m_thread;IHttpServiceListener *m_listener;
};

源文件:HttpService.cpp

#include "StdAfx.h"
#include "HttpService.h"#pragma comment(lib, "httpapi.lib")CHttpService::CHttpService()
{m_thread = NULL;m_req_queue  = NULL;m_req_buffer = NULL;m_req_buffer_size = 4096;
}BOOL CHttpService::Create(INT port, IHttpServiceListener *listener)
{ULONG ret;WCHAR url[1024];HTTPAPI_VERSION version = HTTP_VERSION_1_0;swprintf(url, 1024, L"http://*:%d/", port);ret = HttpInitialize(version,HTTP_INITIALIZE_SERVER,NULL);if(ret != NO_ERROR){TRACE("HttpInitialize error(%u)!\r\n", ret);return FALSE;}ret = HttpCreateHttpHandle(&m_req_queue, 0);if(ret != NO_ERROR){TRACE("HttpCreateHttpHandle error(%u)!\n", ret);HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);return FALSE;}ret = HttpAddUrl(m_req_queue, url, NULL);if(ret != NO_ERROR){TRACE("HttpAddUrl error(%u)!\n", ret);CloseHandle(m_req_queue);HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);return FALSE;}m_req_buffer = (LPBYTE)malloc(m_req_buffer_size);m_listener = listener;m_thread = AfxBeginThread(RecvRequestThread, this);return TRUE;
}BOOL CHttpService::Delete(void)
{if(m_req_queue){CloseHandle(m_req_queue);HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);m_req_queue = NULL;}if(m_req_buffer){free(m_req_buffer);m_req_buffer = NULL;}if(m_thread){m_thread->Delete();m_thread = NULL;}return TRUE;
}BOOL CHttpService::SendRequestResp(HTTP_REQUEST_ID req_id, INT status, LPCSTR reason, LPCSTR type, HANDLE file, LPVOID mem, DWORD mem_size)
{HTTP_RESPONSE   resp;HTTP_DATA_CHUNK chunk;DWORD           ret;DWORD           sent;RtlZeroMemory(&resp, sizeof(resp));resp.StatusCode   = status;resp.pReason      = reason;resp.ReasonLength = (USHORT)strlen(reason);resp.Headers.KnownHeaders[HttpHeaderContentType].pRawValue = type;resp.Headers.KnownHeaders[HttpHeaderContentType].RawValueLength = (USHORT)strlen(type);resp.EntityChunkCount = 1;resp.pEntityChunks    = &chunk;if(file != NULL){chunk.DataChunkType = HttpDataChunkFromFileHandle;chunk.FromFileHandle.FileHandle = file;chunk.FromFileHandle.ByteRange.StartingOffset.QuadPart  = 0;chunk.FromFileHandle.ByteRange.Length.QuadPart = HTTP_BYTE_RANGE_TO_EOF;}if(mem != NULL){chunk.DataChunkType = HttpDataChunkFromMemory;chunk.FromMemory.pBuffer = mem;chunk.FromMemory.BufferLength = mem_size;}ret = HttpSendHttpResponse(m_req_queue, req_id, 0, &resp, NULL,   &sent, NULL, 0, NULL, NULL); if(ret != NO_ERROR){TRACE(L"HttpSendHttpResponse error(%u)!\n", ret);return FALSE;}return TRUE;
}BOOL CHttpService::RecvRequestBody(HTTP_REQUEST_ID req_id, HANDLE file, char *mem, DWORD mem_size)
{DWORD read;if(file != NULL){return FALSE;}if(mem != NULL){HttpReceiveRequestEntityBody(m_req_queue, req_id, 0, mem, mem_size, &read, NULL);mem[read] = 0;return TRUE;}return FALSE;
}UINT CHttpService::RecvRequestThread(LPVOID param)
{CHttpService *self;self = (CHttpService *)param;self->DoReceiveRequests();Sleep(INFINITE);return 0;
}BOOL CHttpService::DoReceiveRequests(void)
{ULONG         ret;DWORD         bytes_read;PHTTP_REQUEST request;request = (PHTTP_REQUEST)m_req_buffer;while(1){RtlZeroMemory(request,m_req_buffer_size);ret = HttpReceiveHttpRequest(m_req_queue,HTTP_NULL_ID,0,request,m_req_buffer_size,&bytes_read,NULL);if(ret == NO_ERROR){m_listener->OnRecvRequest(this,request);continue;}TRACE("HttpReceiveHttpRequest error(%u)!\r\n", ret);if(ret == ERROR_OPERATION_ABORTED){return FALSE;}if(ret == ERROR_INVALID_HANDLE){return FALSE;}}return TRUE;
}BOOL CHttpService::GetRemoteAddr(PHTTP_REQUEST request, CString &text)
{PSOCKADDR_IN addr = (PSOCKADDR_IN)request->Address.pRemoteAddress;text.Format("%d.%d.%d.%d", addr->sin_addr.S_un.S_un_b.s_b1, addr->sin_addr.S_un.S_un_b.s_b2, addr->sin_addr.S_un.S_un_b.s_b3,addr->sin_addr.S_un.S_un_b.s_b4);return TRUE;
}

MFC调用winhttp实现简易的HTTP服务器程序相关推荐

  1. Python简易web静态服务器程序搭建

    Python简易web静态服务器程序搭建 Python自带简易静态web服务器搭建 http.server模块 DIY简易静态web服务器程序搭建 普通版 步骤 具体代码 面向对象版 代码 命令行版 ...

  2. 一个简易的TCP服务器程序(将收到的字符发回给客户端)

    /*-----------------------------------------------------------------运行该程序相当于启动了服务器,用telnet客户端来连接服务器.命 ...

  3. 【通信协议及编码】实验3:MFC框架下聊天室客户机与服务器程序

    文章目录 一.实验目的 二.实验环境 三.实验内容 一.实验目的 掌握MFC套接字编程方法 借助VS2016的MFC应用程序向导创建程序框架: 从CSocket类派生用户自定义的套接字类: 通过CAr ...

  4. MFC调用CFileDialog之后目录居然会改变,调试了好久终于发现是这个问题

    MFC调用CFileDialog之后目录居然会改变,调试了好久终于发现是这个问题,上网搜了下,发现也有人和我出现相同的问题.他的博客如下: http://www.programlife.net/cur ...

  5. 利用MFC调用libvlc.dll作一个简单的播放器

    简单介绍MFC调用libvlc.dll作一个简单的播放器,抛砖引玉,各位VC++达人继续深入研究,Jeremiah对VC++确实不太感兴趣,所以就不做太深入的研究了. 2009.10.29修改:加入c ...

  6. 可以供MFC调用的,QT实现的DLL(qtwinmigrate实现)

    MFC和QT的消息循环机制不同,所以,要让QT写的DLL可以供MFC调用,要做一点特殊的处理 #include <qmfcapp.h> #include <qwinwidget.h& ...

  7. MFC调用Qt生成的dll

    MFC和QT的消息循环机制不同,所以,要让QT写的DLL可以供MFC调用,要做一点特殊的处理 [cpp] view plaincopyprint? #include <qmfcapp.h> ...

  8. MFC调用dos窗口使用printf,cout打印输出

    当我们使用AllocConsole函数调用一个dos窗口时,mfc为我们提供了几个打印函数比如_printf等用来向此终端打印输出信息,但是你会发现标准c语言的printf失效了,是因为mfc在帮我们 ...

  9. express 搭建简易的本地服务器

    express 搭建简易的本地服务器 基于nade.js平台,开发极简的web开发框架 安装node.js(此文章省略) 安装express npm initnpm i express -D 安装成功 ...

最新文章

  1. linux运行c程序a. out,bash:./a.out:在由ld生成的运行可执行文件上没有这样的文件或目录。...
  2. 鸿蒙os2.0通知栏,网友上手鸿蒙手机OS 2.0公测版:界面与EMUI已有明显不同
  3. springboot全局常量_Spring-Boot配置属性和环境变量的加载顺序
  4. 使用ldconfig命令将/usr/local/lib加入到默认库
  5. 「AI原生」时代来临?百度智能云提出AI-Native,发布新一代云基础架构「太行」
  6. python preference界面设置_Android设置界面5分钟搞定--Preferences的使用
  7. 69篇关于微博的研究论文和报告
  8. SylixOS Makefile 源代码解析
  9. Python3.8.0中string与byte相互转换
  10. MySQL删除重复数据
  11. 【论文复现】ReLU、Leaky ReLU、PReLU、RReLU实验对比(2015)
  12. ISO15693卡ICODE SLI-S
  13. Web3.0技术栈简介
  14. 服装行业施行ERP体系的首要好处是什么?
  15. Understanding ISP Pipeline - Noise Reduction
  16. c语言选择题题及答案,C语言选择题及答案
  17. 浅谈汽车质量管理系统-IATF 16949
  18. Python—SJ—实验6—加密解密文本
  19. 马平福书法家中华汉字文化艺术作品欣赏
  20. 读懂消费金融之主流风控方法

热门文章

  1. 计算机中chitu形式简称,ChiTuBox
  2. CSS-BEM命名规范
  3. mysql开窗函数有哪些_mysql开窗函数
  4. 计算机网络 研究生入学考试,中南大学研究生入学考试 《计算机网络》试题
  5. 推荐一个快速部署Java,NodeJS,Python,Scala,.NET等Web应用程序的开源PASS平台
  6. kafka安装及入门
  7. PSO优化的BP神经网络
  8. 回溯法-图的m着色问题
  9. cenntos系统配置dns地址_localhost
  10. 一文看懂区块链技术安全,在安全行业区块链又有什么用