这是微软提供的示例程序,原文地址在此https://msdn.microsoft.com/en-us/library/windows/desktop/aa364640(v=vs.85).aspx

HTTP Server示例程序

以下示例应用程序展示如何使用HTTP Server API处理HTTP请求任务。第一个示例中包含的precomp.h文件包含示例所需的所有头文件,如下:

#ifndef UNICODE
#define UNICODE
#endif #ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif #include <windows.h>
#include <http.h>
#include <stdio.h> #pragma comment(lib, "httpapi.lib")

Main and Preliminaries(main和准备工作)

#include "precomp.h"

//
// Macros.初始化HTTP响应体宏
//
#define INITIALIZE_HTTP_RESPONSE( resp, status, reason ) \
do \
{ \
RtlZeroMemory( (resp), sizeof(*(resp)) ); \
(resp)->StatusCode = (status); \
(resp)->pReason = (reason); \
(resp)->ReasonLength = (USHORT) strlen(reason); \
} while (FALSE) #define ADD_KNOWN_HEADER(Response, HeaderId, RawValue) \
do \
{ \
(Response).Headers.KnownHeaders[(HeaderId)].pRawValue = \
(RawValue);\
(Response).Headers.KnownHeaders[(HeaderId)].RawValueLength = \
(USHORT) strlen(RawValue); \
} while(FALSE) #define ALLOC_MEM(cb) HeapAlloc(GetProcessHeap(), 0, (cb)) #define FREE_MEM(ptr) HeapFree(GetProcessHeap(), 0, (ptr)) //
// Prototypes.原型
//
DWORD DoReceiveRequests(HANDLE hReqQueue); DWORD
SendHttpResponse(
IN HANDLE hReqQueue,
IN PHTTP_REQUEST pRequest,
IN USHORT StatusCode,
IN PSTR pReason,
IN PSTR pEntity
); DWORD
SendHttpPostResponse(
IN HANDLE hReqQueue,
IN PHTTP_REQUEST pRequest
); /*******************************************************************++ 函数说明:
main函数 参数:
argc - 命令行参数个数.
argv - 命令行参数. 返回值:
Success/Failure --*******************************************************************/
int __cdecl wmain(
int argc,
wchar_t * argv[]
)
{
ULONG retCode;
HANDLE hReqQueue = NULL;
int UrlAdded = 0;
HTTPAPI_VERSION HttpApiVersion = HTTPAPI_VERSION_1; if (argc < 2)
{
wprintf(L"%ws: <Url1> [Url2] ... \n", argv[0]);
return -1;
}

初始化HTTP Service

    //
// 初始化HTTP Server APIs
//
retCode = HttpInitialize(
HttpApiVersion,
HTTP_INITIALIZE_SERVER, // Flags
NULL // Reserved
); if (retCode != NO_ERROR)
{
wprintf(L"HttpInitialize failed with %lu \n", retCode);
return retCode;
} //
// 创建请求队列句柄
//
retCode = HttpCreateHttpHandle(
&hReqQueue, // Req Queue
0 // Reserved
); if (retCode != NO_ERROR)
{
wprintf(L"HttpCreateHttpHandle failed with %lu \n", retCode);
goto CleanUp;
}

注册URLs进行监听

    //
// 命令行参数指定要监听的URI。为每个URI调用HttpAddUrl。
//
// URI是一个完全合格的URI,必须包含终止字符(/)
//
for (int i = 1; i < argc; i++)
{
wprintf(L"listening for requests on the following url: %s\n", argv[i]); retCode = HttpAddUrl(
hReqQueue, // Req Queue
argv[i], // Fully qualified URL
NULL // Reserved
); if (retCode != NO_ERROR)
{
wprintf(L"HttpAddUrl failed with %lu \n", retCode);
goto CleanUp;
}
else
{
//
// Track the currently added URLs.
//
UrlAdded ++;
}
}

调用程序以接收请求

    DoReceiveRequests(hReqQueue);

清理HTTP Server API

CleanUp:

    //
// 对所有添加的URI调用HttpRemoveUrl.
//
for(int i=1; i<=UrlAdded; i++)
{
HttpRemoveUrl(
hReqQueue, // Req Queue
argv[i] // Fully qualified URL
);
} //
// 关闭请求队列句柄.
//
if(hReqQueue)
{
CloseHandle(hReqQueue);
} //
// 调用HttpTerminate.
//
HttpTerminate(HTTP_INITIALIZE_SERVER, NULL); return retCode;

接收请求

/*******************************************************************++

函数说明:
他的功能是接收一个请求。
该函数调用相应的函数来处理响应。 参数:
hReqQueue - 请求队列句柄 返回值:
Success/Failure. --*******************************************************************/
DWORD DoReceiveRequests(
IN HANDLE hReqQueue
)
{
ULONG result;
HTTP_REQUEST_ID requestId;
DWORD bytesRead;
PHTTP_REQUEST pRequest;
PCHAR pRequestBuffer;
ULONG RequestBufferLength; //
// 分配一个2 KB缓冲区。 这个大小应该适用于大多数请求。 如果需要,
// 可以增加缓冲区大小。HTTP_REQUEST结构也需要空间。
//
RequestBufferLength = sizeof(HTTP_REQUEST) + 2048;
pRequestBuffer = (PCHAR) ALLOC_MEM( RequestBufferLength ); if (pRequestBuffer == NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
} pRequest = (PHTTP_REQUEST)pRequestBuffer; //
// 等待一个新请求. 标记为一个NULL请求ID
// HTTP_SET_NULL_ID( &requestId ); for(;;)
{
RtlZeroMemory(pRequest, RequestBufferLength); result = HttpReceiveHttpRequest(
hReqQueue, // Req Queue
requestId, // Req ID
0, // Flags
pRequest, // HTTP request buffer
RequestBufferLength,// req buffer length
&bytesRead, // bytes received
NULL // LPOVERLAPPED
);

处理HTTP请求

        if(NO_ERROR == result)
{
//
// Worked!
//
switch(pRequest->Verb)
{
/* GET 请求处理 */
case HttpVerbGET:
wprintf(L"Got a GET request for %ws \n",
pRequest->CookedUrl.pFullUrl); result = SendHttpResponse(
hReqQueue,
pRequest,
200,
"OK",
"Hey! You hit the server \r\n"
);
break; /* POST 请求处理 */
case HttpVerbPOST: wprintf(L"Got a POST request for %ws \n",
pRequest->CookedUrl.pFullUrl); result= SendHttpPostResponse(hReqQueue, pRequest);
break; default:
wprintf(L"Got a unknown request for %ws \n",
pRequest->CookedUrl.pFullUrl); result = SendHttpResponse(
hReqQueue,
pRequest,
503,
"Not Implemented",
NULL
);
break;
} if(result != NO_ERROR)
{
break;
} //
// 重置请求ID用于处理下一个请求.
//
HTTP_SET_NULL_ID( &requestId );
}
else if(result == ERROR_MORE_DATA)
{
//
// 输入缓冲区太小,无法容纳请求标头。增加缓冲区大小,再次调用API。
//
// 再次调用API时,通过传递RequestID来处理失败的请求。
//
// 该RequestID从旧缓冲区读取。
//
requestId = pRequest->RequestId; //
// 释放旧的缓冲区并分配一个新的缓冲区。
//
RequestBufferLength = bytesRead;
FREE_MEM( pRequestBuffer );
pRequestBuffer = (PCHAR) ALLOC_MEM( RequestBufferLength ); if (pRequestBuffer == NULL)
{
result = ERROR_NOT_ENOUGH_MEMORY;
break;
} pRequest = (PHTTP_REQUEST)pRequestBuffer; }
else if(ERROR_CONNECTION_INVALID == result &&
!HTTP_IS_NULL_ID(&requestId))
{
// 当尝试使用更多缓冲区来处理请求时,TCP连接被对方破坏
// 继续下一个请求。 HTTP_SET_NULL_ID( &requestId );
}
else
{
break;
} } if(pRequestBuffer)
{
FREE_MEM( pRequestBuffer );
} return result;
}

发送一个HTTP响应

/*******************************************************************++

函数说明:
这个函数用于发送一个HTTP响应 参数:
hReqQueue - 请求队列句柄
pRequest - 解析出的HTTP请求
StatusCode - Response状态码
pReason - Response原因短语
pEntityString - Response实体主体 返回值:
Success/Failure.
--*******************************************************************/ DWORD SendHttpResponse(
IN HANDLE hReqQueue,
IN PHTTP_REQUEST pRequest,
IN USHORT StatusCode,
IN PSTR pReason,
IN PSTR pEntityString
)
{
HTTP_RESPONSE response;
HTTP_DATA_CHUNK dataChunk;
DWORD result;
DWORD bytesSent; //
// 初始化HTTP response结构体
//
INITIALIZE_HTTP_RESPONSE(&response, StatusCode, pReason); //
// 添加一个known header.
//
ADD_KNOWN_HEADER(response, HttpHeaderContentType, "text/html"); if(pEntityString)
{
//
// 添加一个entity chunk.
//
dataChunk.DataChunkType = HttpDataChunkFromMemory;
dataChunk.FromMemory.pBuffer = pEntityString;
dataChunk.FromMemory.BufferLength =
(ULONG) strlen(pEntityString); response.EntityChunkCount = 1;
response.pEntityChunks = &dataChunk;
} //
// 因为entity body在一个调用中发送,所以不需要指定Content-Length。
// result = HttpSendHttpResponse(
hReqQueue, // ReqQueueHandle
pRequest->RequestId, // Request ID
0, // Flags
&response, // HTTP response
NULL, // pReserved1
&bytesSent, // bytes sent (OPTIONAL)
NULL, // pReserved2 (must be NULL)
0, // Reserved3 (must be 0)
NULL, // LPOVERLAPPED(OPTIONAL)
NULL // pReserved4 (must be NULL)
); if(result != NO_ERROR)
{
wprintf(L"HttpSendHttpResponse failed with %lu \n", result);
} return result;
}

发送一个HTTP POST响应

#define MAX_ULONG_STR ((ULONG) sizeof("4294967295"))

/*******************************************************************++

函数说明:
这个函数在读取entity body后发送HTTP响应 参数:
hReqQueue - 请求队列句柄
pRequest - 解析出的HTTP request. 返回值:
Success/Failure.
--*******************************************************************/ DWORD SendHttpPostResponse(
IN HANDLE hReqQueue,
IN PHTTP_REQUEST pRequest
)
{
HTTP_RESPONSE response;
DWORD result;
DWORD bytesSent;
PUCHAR pEntityBuffer;
ULONG EntityBufferLength;
ULONG BytesRead;
ULONG TempFileBytesWritten;
HANDLE hTempFile;
TCHAR szTempName[MAX_PATH + 1];
CHAR szContentLength[MAX_ULONG_STR];
HTTP_DATA_CHUNK dataChunk;
ULONG TotalBytesRead = 0; BytesRead = 0;
hTempFile = INVALID_HANDLE_VALUE; //
// 为实体缓冲区分配空间。 缓冲区可按需增加。
//
EntityBufferLength = 2048;
pEntityBuffer = (PUCHAR) ALLOC_MEM( EntityBufferLength ); if (pEntityBuffer == NULL)
{
result = ERROR_NOT_ENOUGH_MEMORY;
wprintf(L"Insufficient resources \n");
goto Done;
} //
// 初始化HTTP response结构体.
//
INITIALIZE_HTTP_RESPONSE(&response, 200, "OK"); //
// 对于POST,从客户端回显实体
//
// 注意: 如果HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY标识通过HttpReceiveHttpRequest()
// 传递,则entity将是HTTP_REQUEST的一部分(使用pEntityChunks字段).因为此标识
// 未被传递,则entity不在HTTP_REQUEST中.
// if(pRequest->Flags & HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS)
{
// 实体主体通过多个调用发送. 收集这些在一个文件并回发.创建一个临时文件
// if(GetTempFileName(
L".",
L"New",
0,
szTempName
) == 0)
{
result = GetLastError();
wprintf(L"GetTempFileName failed with %lu \n", result);
goto Done;
} hTempFile = CreateFile(
szTempName,
GENERIC_READ | GENERIC_WRITE,
0, // Do not share.
NULL, // No security descriptor.
CREATE_ALWAYS, // Overrwrite existing.
FILE_ATTRIBUTE_NORMAL, // Normal file.
NULL
); if(hTempFile == INVALID_HANDLE_VALUE)
{
result = GetLastError();
wprintf(L"Cannot create temporary file. Error %lu \n",
result);
goto Done;
} do
{
//
// 从请求中读取entity chunk.
//
BytesRead = 0;
result = HttpReceiveRequestEntityBody(
hReqQueue,
pRequest->RequestId,
0,
pEntityBuffer,
EntityBufferLength,
&BytesRead,
NULL
); switch(result)
{
case NO_ERROR: if(BytesRead != 0)
{
TotalBytesRead += BytesRead;
WriteFile(
hTempFile,
pEntityBuffer,
BytesRead,
&TempFileBytesWritten,
NULL
);
}
break; case ERROR_HANDLE_EOF: //
// The last request entity body has been read.
// Send back a response.
//
// To illustrate entity sends via
// HttpSendResponseEntityBody, the response will
// be sent over multiple calls. To do this,
// pass the HTTP_SEND_RESPONSE_FLAG_MORE_DATA
// flag. if(BytesRead != 0)
{
TotalBytesRead += BytesRead;
WriteFile(
hTempFile,
pEntityBuffer,
BytesRead,
&TempFileBytesWritten,
NULL
);
} //
// Because the response is sent over multiple
// API calls, add a content-length.
//
// Alternatively, the response could have been
// sent using chunked transfer encoding, by
// passimg "Transfer-Encoding: Chunked".
// // NOTE: Because the TotalBytesread in a ULONG
// are accumulated, this will not work
// for entity bodies larger than 4 GB.
// For support of large entity bodies,
// use a ULONGLONG.
// sprintf_s(szContentLength, MAX_ULONG_STR, "%lu", TotalBytesRead); ADD_KNOWN_HEADER(
response,
HttpHeaderContentLength,
szContentLength
); result =
HttpSendHttpResponse(
hReqQueue, // ReqQueueHandle
pRequest->RequestId, // Request ID
HTTP_SEND_RESPONSE_FLAG_MORE_DATA,
&response, // HTTP response
NULL, // pReserved1
&bytesSent, // bytes sent-optional
NULL, // pReserved2
0, // Reserved3
NULL, // LPOVERLAPPED
NULL // pReserved4
); if(result != NO_ERROR)
{
wprintf(
L"HttpSendHttpResponse failed with %lu \n",
result
);
goto Done;
} //
// Send entity body from a file handle.
//
dataChunk.DataChunkType =
HttpDataChunkFromFileHandle; dataChunk.FromFileHandle.
ByteRange.StartingOffset.QuadPart = 0; dataChunk.FromFileHandle.
ByteRange.Length.QuadPart =
HTTP_BYTE_RANGE_TO_EOF; dataChunk.FromFileHandle.FileHandle = hTempFile; result = HttpSendResponseEntityBody(
hReqQueue,
pRequest->RequestId,
0, // This is the last send.
1, // Entity Chunk Count.
&dataChunk,
NULL,
NULL,
0,
NULL,
NULL
); if(result != NO_ERROR)
{
wprintf(
L"HttpSendResponseEntityBody failed %lu\n",
result
);
} goto Done; break; default:
wprintf(
L"HttpReceiveRequestEntityBody failed with %lu \n",
result);
goto Done;
} } while(TRUE);
}
else
{
// 此请求没有实体主体。
// result = HttpSendHttpResponse(
hReqQueue, // ReqQueueHandle
pRequest->RequestId, // Request ID
0,
&response, // HTTP response
NULL, // pReserved1
&bytesSent, // bytes sent (optional)
NULL, // pReserved2
0, // Reserved3
NULL, // LPOVERLAPPED
NULL // pReserved4
);
if(result != NO_ERROR)
{
wprintf(L"HttpSendHttpResponse failed with %lu \n",
result);
}
} Done: if(pEntityBuffer)
{
FREE_MEM(pEntityBuffer);
} if(INVALID_HANDLE_VALUE != hTempFile)
{
CloseHandle(hTempFile);
DeleteFile(szTempName);
} return result;
}

WinHttp编写HTTP服务器示例代码的更多相关文章

  1. 程序员笔记|如何编写高性能的Java代码

    一.并发 Unable to create new native thread …… 问题1:Java中创建一个线程消耗多少内存? 每个线程有独自的栈内存,共享堆内存 问题2:一台机器可以创建多少线程 ...

  2. WebRTC 音频采样算法 附完整C++示例代码

    之前有大概介绍了音频采样相关的思路,详情见<简洁明了的插值音频重采样算法例子 (附完整C代码)>. 音频方面的开源项目很多很多. 最知名的莫过于谷歌开源的WebRTC, 其中的音频模块就包 ...

  3. 推荐Java五大微服务器及其代码示例教程

    来源素文宅博客:http://blog.yoodb.com/yoodb/article/detail/1339 微服务越来越多地用于开发领域,因为开发人员致力于创建更大,更复杂的应用程序,这些应用程序 ...

  4. python开源项目及示例代码

    本页面是俺收集的各种 Python 资源,不定期更新. 下面列出的各种 Python 库/模块/工具,如果名称带超链接,说明是第三方的:否则是 Python 语言内置的. 1 算法 1.1 字符串处理 ...

  5. C/C++ 开源库及示例代码

    C/C++ 开源库及示例代码 Table of Contents 说明 1 综合性的库 2 数据结构 & 算法 2.1 容器 2.1.1 标准容器 2.1.2 Lockfree 的容器 2.1 ...

  6. iOS App集成Apple Pay教程(附示例代码)

    苹果在本周一发布了iOS 8.1版本,并正式开放了Apple Pay支付系统.Apple Pay是一个基于NFC的支付系统,不久将被数以万计的线下零售商店予以支持.即便这项科技并不是彻底的突破性进展, ...

  7. 实战WEB 服务器(JAVA编写WEB服务器)

    实战WEB 服务器(JAVA编写WEB服务器) 标签: web服务服务器javawebsockethttp服务器 2010-04-21 17:09 11631人阅读 评论(24) 收藏 举报  分类: ...

  8. python开源项目及示例代码(转)

    本页面是俺收集的各种 Python 资源,不定期更新. 下面列出的各种 Python 库/模块/工具,如果名称带超链接,说明是第三方的:否则是 Python 语言内置的. 1 算法 1.1 字符串处理 ...

  9. 如何在Android上编写高效的Java代码

    转自:http://www.ituring.com.cn/article/177180 作者/ Erik Hellman Factor10咨询公司资深移动开发顾问,曾任索尼公司Android团队首席架 ...

随机推荐

  1. ADB与AVD的常见问题

    一.adb问题常用解决方法 若是模拟器启动正常,但是adb检测不到模拟器,我们给他一套不解释连招,下面教大家几招基础拳法. 1.基础拳法一:循环自动检测 下图那个小按钮,点它,狠狠的点它,然后点运行, ...

  2. perf使用示例2

    perf使用示例2 性能调优工具如 perf,Oprofile 等的基本原理都是对被监测对象进行采样,最简单的情形是根据 tick 中断进行采样,即在 tick 中断内触发采样点,在采样点里判断程序当 ...

  3. java操作mongodb(连接池)(转)

    原文链接: java操作mongodb(连接池) Mongo的实例其实就是一个数据库连接池,这个连接池里默认有10个链接.我们没有必要重新实现这个链接池,但是我们可以更改这个连接池的配置.因为Mong ...

  4. OpenCV教程(47) sift特征和surf特征

         在前面三篇教程中的几种角检测方法,比如harris角检测,都是旋转无关的,即使我们转动图像,依然能检测出角的位置,但是图像缩放后,harris角检测可能会失效,比如下面的图像,图像放大之前可 ...

  5. 7.3 netty3基本使用

    由于dubbo默认使用的是netty3进行通信的,这里简单的列出一个netty3通信的例子. 一 server端 1 Server package com.hulk.netty.server; imp ...

  6. 华清远见Linux设备驱动(每章小结)

    1.  linux设备驱动是以内核模块的方式而存在的,在具体的驱动开发中将驱动编译为模块具有很到的工程意义.因为如果将正在开发中的驱动编译如内核,而开发过程中会不断修改驱动代码,则需要不断的编译和重启 ...

  7. 一个可用来记录Isilon各个节点的CPU,网络,磁盘性能的命令

    通过查看命令isi statistics system的帮助信息,拼出了下面的命令. isi statistics system list --nodes=all --degraded --forma ...

  8. iOS开发-UITextView实现PlaceHolder的方式

    之前开发遇到过UITextField中加入一个PlaceHolder的问题,直接设置一下即可,不过这次是需要在UITextView中实现一个PlaceHolder,跟之前有点不同.在网上参考了各位前辈 ...

  9. 在UTF-8中,一个汉字为什么需要三个字节?(转)

    http://www.cnblogs.com/web21/p/6092414.html UNICODE是万能编码,包含了所有符号的编码,它规定了所有符号在计算机底层的二进制的表示顺序.有关Unicod ...

  10. 【图片识别】Java中使用tess4J进行图片文字识别(支持中文)(转)

    http://blog.csdn.net/wsk1103/article/details/54173282 java中识别文字比较简单,使用的软件是tesseractocr(使用的版本是3.02,3以 ...