使用HP搭建Socket HttpServer,并且实现post,get,以及websocket,主要是webssockt折腾了不少时间。
首先要自己实现底层接口,都是纯虚函数,需要自己去实现,继承自IHttpServerListener
#pragma once
#include "SocketInterface.h"
#include "stdio.h"
#include
#include "BASE64.h"
#include "USER_SHA1.h"
#define html_base_path "f:\\Desktop\\桌面文件整理\\临时工程\\helsinki-blue\\"
/************************************************************************
名称:IComplexHttp 组件监听器基接口
描述:定义 IComplexHttp 组件监听器的所有事件
************************************************************************/
class HttpServerListernet : public IHttpServerListener
{
/**********************************************************************/
/* Give a client a 404 not found status message. */
/**********************************************************************/
void not_found(IHttpServer* pSender, CONNID dwConnID)
{
const char *pErrorNotFound =
"Not Found \r\n"\
"The server could not fulfill\r\n"\
"your request because the resource specified\r\n"\
"is unavailable or nonexistent.\r\n"\
"\r\n";
pSender->SendResponse(dwConnID, HSC_OK, nullptr, nullptr, 0, (BYTE *)pErrorNotFound, sizeof(pErrorNotFound));
}
public:
/*
* 名称:开始解析通知
* 描述:开始解析 HTTP 报文时,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* 返回值: HPR_OK -- 继续执行
* HPR_ERROR -- 引发 OnParserError() 和 OnClose() 事件并关闭连接
*/
EnHttpParseResult OnMessageBegin(IHttpServer* pSender, CONNID dwConnID)
{
return HPR_OK;
}
/*
* 名称:请求行解析完成通知(仅用于 HTTP 服务端)
* 描述:请求行解析完成后,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* lpszMethod -- 请求方法名
* lpszUrl -- 请求行中的 URL 域
* 返回值: HPR_OK -- 继续执行
* HPR_ERROR -- 引发 OnParserError() 和 OnClose() 事件并关闭连接
*/
//过滤器在此完成
EnHttpParseResult OnRequestLine(IHttpServer* pSender, CONNID dwConnID, LPCSTR lpszMethod, LPCSTR lpszUrl)
{
char buff[512 + 4];
char UrlData[1024 + 4];
char *pParameter = nullptr; //参数
char ExtenName[4];
char path[512];
int len;
struct stat st;
if (lpszMethod != nullptr)
{
if (strcmp(lpszMethod, "POST") == 0) //POST
{
//pSender->SendResponse(dwConnID, HSC_OK, nullptr, nullptr, 0, nullptr);
return HPR_OK;
}
else if (strcmp(lpszMethod, "GET") == 0) //GET
{
len = strlen(lpszUrl);
if (len > 1024) //限制长度为1KB
{
len = 1024;
}
if (len > 0)
{
//拷贝数据到缓冲区中
memcpy(UrlData, lpszUrl, len);
UrlData[len] = 0;
if (lpszUrl[len - 1] == '/') //当前请求的是目录,打开默认文件
{
if (strcmp(UrlData, "/websocket/data/") == 0) //websocket api接口
{
//pSender->Send(dwConnID, (BYTE *)"123456\r\n", 8, 0);
//pSender->SendWSMessage(dwConnID, true, 0, 0, nullptr, (BYTE *)"123456\r\n", 8, 0);
return HPR_OK;
}
else
{
sprintf_s(path, 512, "%s%s", html_base_path, "index.html");
}
}
else //非目录,先处理参数,去掉参数后判断是文件还是虚拟路径URL
{
pParameter = strstr(UrlData, "?"); //搜索到第一个问号,问号后面的都是参数
if (pParameter != nullptr) //有参数
{
*pParameter = '\0'; //截断数据-前面的是URL,后面的是参数,并且去掉了第一个问号
pParameter += 1; //跳过问号
}
sprintf_s(path, 512, "%s%s", html_base_path, UrlData); //生成文件绝对路径
}
if (stat(path, &st) == -1) //文件不存在
{
not_found(pSender, dwConnID); //返回404
}
else //文件存在
{
pSender->SendLocalFile(dwConnID, path, HSC_OK, nullptr, nullptr, 0);//返回文件
}
}
return HPR_OK;
}
}
return HPR_ERROR;
}
/*
* 名称:BODY 报文通知
* 描述:每当接收到 HTTP BODY 报文,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* pData -- 数据缓冲区
* iLength -- 数据长度
* 返回值: HPR_OK -- 继续执行
* HPR_ERROR -- 引发 OnParserError() 和 OnClose() 事件并关闭连接
*/
//收到POST请求负载
EnHttpParseResult OnBody(IHttpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
{
//pSender->Send(dwConnID, (BYTE *)"123456\r\n", 8, 0);
pSender->SendResponse(dwConnID, HSC_OK, nullptr, nullptr, 0, pData, iLength);
//pSender->SendLocalFile(dwConnID, "f:\\Desktop\\桌面文件夹整理\\青岛站点4.png", HSC_OK, nullptr, nullptr, 0);
return HPR_OK;
}
/*
* 名称:状态行解析完成通知(仅用于 HTTP 客户端)
* 描述:状态行解析完成后,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* usStatusCode -- HTTP 状态码
* lpszDesc -- 状态描述
* 返回值: HPR_OK -- 继续执行
* HPR_ERROR -- 引发 OnParserError() 和 OnClose() 事件并关闭连接
*/
EnHttpParseResult OnStatusLine(IHttpServer* pSender, CONNID dwConnID, USHORT usStatusCode, LPCSTR lpszDesc)
{
return HPR_OK;
}
/*
* 名称:请求头通知
* 描述:每当解析完成一个请求头后,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* lpszName -- 请求头名称
* lpszValue -- 请求头值
* 返回值: HPR_OK -- 继续执行
* HPR_ERROR -- 引发 OnParserError() 和 OnClose() 事件并关闭连接
*/
EnHttpParseResult OnHeader(IHttpServer* pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)
{
if (strcmp("Sec-WebSocket-Key", lpszName) == 0) //收到websocket握手
{
THeader lpHeaders[4];
BYTE OutSHA1Buf[512];
static char key[256];
lpHeaders[0].name = "Upgrade";
lpHeaders[0].value = "websocket";
lpHeaders[1].name = "Connection";
lpHeaders[1].value = "Upgrade";
lpHeaders[2].name = "Sec-WebSocket-Accept";
sprintf_s(key, 255, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", lpszValue);
int len = SHA1_String((unsigned char*)key, strlen(key), OutSHA1Buf);
base64_encode(OutSHA1Buf, 20, key);
lpHeaders[2].value = key; //生成握手加密key
lpHeaders[3].name = "Sec-WebSocket-Protocol";
lpHeaders[3].value = "chat";
pSender->SendResponse(dwConnID, HSC_SWITCHING_PROTOCOLS, nullptr, lpHeaders, 3, nullptr, 0);
return HPR_OK;
}
return HPR_OK;
}
/*
* 名称:请求头完成通知
* 描述:解析完成所有请求头后,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* 返回值: HPR_OK -- 继续执行
* HPR_SKIP_BODY -- 跳过当前请求的 HTTP BODY
* HPR_UPGRADE -- 升级协议
* HPR_ERROR -- 引发 OnParserError() 和 OnClose() 事件并关闭连接
*/
EnHttpParseResult OnHeadersComplete(IHttpServer* pSender, CONNID dwConnID)
{
return HPR_OK;
}
/*
* 名称:Chunked 报文头通知
* 描述:每当解析出一个 Chunked 报文头,向监听器发送该通知THeader lpHeaders[4];
lpHeaders[0].name = "Upgrade";
lpHeaders[0].value = "websocket";
lpHeaders[1].name = "Connection";
lpHeaders[1].value = "Upgrade";
lpHeaders[2].name = "Sec-WebSocket-Accept";
lpHeaders[2].value = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="; //生成握手加密key
lpHeaders[3].name = "Sec-WebSocket-Protocol";
lpHeaders[3].value = "chat";
pSender->SendResponse(dwConnID, HSC_SWITCHING_PROTOCOLS, nullptr, lpHeaders, 4, nullptr, 0);
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* iLength -- Chunked 报文体数据长度
* 返回值: HPR_OK -- 继续执行
* HPR_ERROR -- 引发 OnParserError() 和 OnClose() 事件并关闭连接
*/
EnHttpParseResult OnChunkHeader(IHttpServer* pSender, CONNID dwConnID, int iLength)
{
return HPR_OK;
}
/*
* 名称:Chunked 报文结束通知
* 描述:每当解析完一个 Chunked 报文,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* 返回值: HPR_OK -- 继续执行
* HPR_ERROR -- 引发 OnParserError() 和 OnClose() 事件并关闭连接
*/
EnHttpParseResult OnChunkComplete(IHttpServer* pSender, CONNID dwConnID)
{
return HPR_OK;
}
/*
* 名称:完成解析通知
* 描述:每当解析完成一个完整 HTTP 报文,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* 返回值: HPR_OK -- 继续执行
* HPR_ERROR -- 引发 OnParserError() 和 OnClose() 事件并关闭连接
*/
EnHttpParseResult OnMessageComplete(IHttpServer* pSender, CONNID dwConnID)
{
//pSender->Send(dwConnID, (BYTE *)"123456\r\n", 8, 0);
//pSender->SendSmallFile(dwConnID, L"f:\\Desktop\\桌面文件夹整理\\新建文本文档 (3).html", nullptr, nullptr);
return HPR_OK;
}
/*
* 名称:升级协议通知
* 描述:当需要升级协议时,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* enUpgradeType -- 协议类型
* 返回值: HPR_OK -- 继续执行
* HPR_ERROR -- 引发 OnClose() 事件并关闭连接
*/
EnHttpParseResult OnUpgrade(IHttpServer* pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)
{
return HPR_OK;
}
/*
* 名称:解析错误通知
* 描述:当解析 HTTP 报文错误时,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* iErrorCode -- 错误代码
* lpszErrorDesc -- 错误描述
* 返回值: HPR_OK -- 继续执行
* HPR_ERROR -- 引发 OnClose() 事件并关闭连接
*/
EnHttpParseResult OnParseError(IHttpServer* pSender, CONNID dwConnID, int iErrorCode, LPCSTR lpszErrorDesc)
{
return HPR_OK;
}
/*
* 名称:WebSocket 数据包头通知
* 描述:当解析 WebSocket 数据包头时,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* bFinal -- 是否结束帧
* iReserved -- RSV1/RSV2/RSV3 各 1 位
* iOperationCode -- 操作码:0x0 - 0xF
* lpszMask -- 掩码(nullptr 或 4 字节掩码,如果为 nullptr 则没有掩码)
* ullBodyLen -- 消息体长度
* 返回值: HR_OK / HR_IGNORE -- 继续执行
* HR_ERROR -- 引发 OnClose() 事件并关闭连接
*/
EnHandleResult OnWSMessageHeader(IHttpServer* pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
{
static char buff[32];
static int cnt = 0;
//iOperationCode 0:连接帧;1:文本帧;2:二进制数据;8:关闭;9:ping;10:pong
if (iOperationCode == 8) //断开连接
{
return HR_ERROR;
}
int len = sprintf_s(buff, 31, "%d", cnt++);
BYTE MaskingKey[] = { 11, 121, 24, 191 };
//注意:服务器发送到从机是不需要掩码
int status = pSender->SendWSMessage(dwConnID, 1, 0, 1, nullptr, (BYTE*)buff, len, len);
return HR_OK;
}
/*
* 名称:WebSocket 数据包体通知
* 描述:当接收到 WebSocket 数据包体时,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* pData -- 消息体数据缓冲区
* iLength -- 消息体数据长度
* 返回值: HR_OK / HR_IGNORE -- 继续执行
* HR_ERROR -- 引发 OnClose() 事件并关闭连接
*/
EnHandleResult OnWSMessageBody(IHttpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
{
/*char buff[32];
static int cnt = 0;
int len = sprintf_s(buff, 31, "%d", cnt++);
BYTE MaskingKey[] = {11,121,24,191};
int status = pSender->SendWSMessage(dwConnID, false, 0, 2, MaskingKey, (BYTE*)buff, len, len);*/
return HR_OK;
}
/*
* 名称:WebSocket 数据包完成通知
* 描述:当完整接收一个 WebSocket 数据包时,向监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* 返回值: HR_OK / HR_IGNORE -- 继续执行
* HR_ERROR -- 引发 OnClose() 事件并关闭连接
*/
EnHandleResult OnWSMessageComplete(IHttpServer* pSender, CONNID dwConnID)
{
return HR_OK;
}
/*
* 名称:准备监听通知
* 描述:通信服务端组件启动时,在监听 Socket 创建完成并开始执行监听前,Socket 监听
* 器将收到该通知,监听器可以在通知处理方法中执行 Socket 选项设置等额外工作
*
* 参数: pSender -- 事件源对象
* soListen -- 监听 Socket
* 返回值: HR_OK / HR_IGNORE -- 继续执行
* HR_ERROR -- 终止启动通信服务组件
*/
EnHandleResult OnPrepareListen(ITcpServer* pSender, SOCKET soListen)
{
return HR_OK;
}
/*
* 名称:接收连接通知
* 描述:接收到客户端连接请求时,Socket 监听器将收到该通知,监听器可以在通知处理方
* 法中执行 Socket 选项设置或拒绝客户端连接等额外工作
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* soClient -- TCP: 客户端 Socket 句柄,UDP: 客户端 Socket SOCKADDR 指针
* 返回值: HR_OK / HR_IGNORE -- 接受连接
* HR_ERROR -- 拒绝连接
*/
EnHandleResult OnAccept(ITcpServer* pSender, CONNID dwConnID, UINT_PTR soClient)
{
return HR_OK;
}
/*
* 名称:握手完成通知
* 描述:连接完成握手时,Socket 监听器将收到该通知,监听器接收到该通知后才能开始
* 数据收发操作
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* 返回值: HR_OK / HR_IGNORE -- 继续执行
* HR_ERROR -- 引发 OnClose() 事件并关闭连接
*/
EnHandleResult OnHandShake(ITcpServer* pSender, CONNID dwConnID)
{
return HR_OK;
}
/*
* 名称:已发送数据通知
* 描述:成功发送数据后,Socket 监听器将收到该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* pData -- 已发送数据缓冲区
* iLength -- 已发送数据长度
* 返回值: HR_OK / HR_IGNORE -- 继续执行
* HR_ERROR -- 该通知不允许返回 HR_ERROR(调试模式下引发断言错误)
*/
EnHandleResult OnSend(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
{
return HR_OK;
}
/*
* 名称:数据到达通知(PUSH 模型)
* 描述:对于 PUSH 模型的 Socket 通信组件,成功接收数据后将向 Socket 监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* pData -- 已接收数据缓冲区
* iLength -- 已接收数据长度
* 返回值: HR_OK / HR_IGNORE -- 继续执行
* HR_ERROR -- 引发 OnClose() 事件并关闭连接
*/
EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, const BYTE* pData, int iLength)
{
return HR_OK;
}
/*
* 名称:数据到达通知(PULL 模型)
* 描述:对于 PULL 模型的 Socket 通信组件,成功接收数据后将向 Socket 监听器发送该通知
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* iLength -- 已接收数据长度
* 返回值: HR_OK / HR_IGNORE -- 继续执行
* HR_ERROR -- 引发 OnClose() 事件并关闭连接
*/
EnHandleResult OnReceive(ITcpServer* pSender, CONNID dwConnID, int iLength)
{
return HR_OK;
}
/*
* 名称:通信错误通知
* 描述:通信发生错误后,Socket 监听器将收到该通知,并关闭连接
*
* 参数: pSender -- 事件源对象
* dwConnID -- 连接 ID
* enOperation -- Socket 操作类型
* iErrorCode -- 错误代码
* 返回值: 忽略返回值
*/
EnHandleResult OnClose(ITcpServer* pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
{
return HR_OK;
}
/*
* 名称:关闭通信组件通知
* 描述:通信组件关闭时,Socket 监听器将收到该通知
*
* 参数: pSender -- 事件源对象
* 返回值:忽略返回值
*/
EnHandleResult OnShutdown(ITcpServer* pSender)
{
return HR_OK;
}
public:
~HttpServerListernet() {}
};
做websocket握手时需要使用到SHA1与BASE64,这2个都是网上找的。
//USER_SHA1.cpp
#include "StdAfx.h"
#include "USER_SHA1.h"
#include "string.h"
typedef struct SHAstate_st
{
unsigned long h[SHA1_SIZE_BYTE / 4]; /* 存放摘要结果(32*5=160 bits)*/
unsigned long Nl;
unsigned long Nh; /*存放信息总位数,Nh:高32位,Nl:低32位*/
unsigned long data[16]; /*数据从第0个的高8位开始依次放置*/
int FlagInWord; /*标识一个data元素中占用的字节数(从高->低),取值0,1,2,3*/
int msgIndex; /*当前已填充满的data数组元素数。*/
int isTooMang; /*正常为0,当处理的信息超过2^64 bits时为1;*/
} SHA1_Context;
#define INIT_DATA_h0 0x67452301U
#define INIT_DATA_h1 0xEFCDAB89U
#define INIT_DATA_h2 0x98BADCFEU
#define INIT_DATA_h3 0x10325476U
#define INIT_DATA_h4 0xC3D2E1F0U
#define SHA1CircularShift(bits, word) (((word) << (bits)) | ((word) >> (32 - (bits))))
const unsigned long SHA1_Kt[] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
typedef unsigned long(*SHA1_pFun)(unsigned long b, unsigned long c, unsigned long d);
/*定义四个函数*/
static unsigned long SHA1_ft0_19(unsigned long b, unsigned long c, unsigned long d)
{
return (b&c) | ((~b)&d);
}
static unsigned long SHA1_ft20_39(unsigned long b, unsigned long c, unsigned long d)
{
return b ^ c ^ d;
}
static unsigned long SHA1_ft40_59(unsigned long b, unsigned long c, unsigned long d)
{
return (b&c) | (b&d) | (c&d);
}
static unsigned long SHA1_ft60_79(unsigned long b, unsigned long c, unsigned long d)
{
return b ^ c ^ d;
}
SHA1_pFun ft[] = { SHA1_ft0_19, SHA1_ft20_39, SHA1_ft40_59, SHA1_ft60_79 };
static int SHA1_Init(SHA1_Context *c)
{
if (NULL == c)
{
return -1;
}
c->h[0] = INIT_DATA_h0;
c->h[1] = INIT_DATA_h1;
c->h[2] = INIT_DATA_h2;
c->h[3] = INIT_DATA_h3;
c->h[4] = INIT_DATA_h4;
c->Nl = 0;
c->Nh = 0;
c->FlagInWord = 0;
c->msgIndex = 0;
c->isTooMang = 0;
memset(c->data, 0, 64);
return 1;
}
int SHA1_GetMsgBits(SHA1_Context *c)
{
int a = 0;
if ((NULL == c) || (0 != c->isTooMang))
{
return -1;
}
a = sizeof(unsigned long) * 8 * c->msgIndex + 8 * c->FlagInWord;
return a;
}
int SHA1_Clear_data(SHA1_Context *c)
{
if (NULL == c)
{
return -1;
}
memset(c->data, 0, 64);
c->msgIndex = 0;
c->FlagInWord = 0;
return 1;
}
int SHA1_One(SHA1_Context *c)
{
unsigned long AE[5];
unsigned long w[80];
unsigned long temp = 0;
int t = 0;
if ((NULL == c) || (0 != c->isTooMang))
{
return -1;
}
for (t = 0; t < 16; ++t)
{
w[t] = c->data[t];
}
for (t = 16; t < 80; ++t)
{
w[t] = SHA1CircularShift(1, w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]);
}
for (t = 0; t < 5; ++t)
{
AE[t] = c->h[t];
}
for (t = 0; t <= 79; ++t)
{
temp = SHA1CircularShift(5, AE[0]) + (*ft[t / 20])(AE[1], AE[2], AE[3]) + AE[4] + w[t] + SHA1_Kt[t / 20];
AE[4] = AE[3];
AE[3] = AE[2];
AE[2] = SHA1CircularShift(30, AE[1]);
AE[1] = AE[0];
AE[0] = temp;
}
for (t = 0; t < 5; ++t)
{
c->h[t] += AE[t];
}
SHA1_Clear_data(c);
return 1;
}
int SHA1_PadMessage(SHA1_Context *c)
{
int msgBits = -1;
if ((NULL == c) || (0 != c->isTooMang))
{
return -1;
}
msgBits = SHA1_GetMsgBits(c);
if (440 < msgBits)
{
c->data[c->msgIndex++] |= (1 << (8 * (4 - c->FlagInWord) - 1));
c->FlagInWord = 0;
while (c->msgIndex < 16)
{
c->data[c->msgIndex++] = 0;
}
SHA1_One(c);
while (c->msgIndex < 14)
{
c->data[c->msgIndex++] = 0;
}
}
else
{
c->data[c->msgIndex++] |= (1 << (8 * (4 - c->FlagInWord) - 1));
c->FlagInWord = 0;
while (c->msgIndex < 14)
{
c->data[c->msgIndex++] = 0;
}
}
while (c->msgIndex < 14)
{
c->data[c->msgIndex++] = 0;
}
c->data[c->msgIndex++] = c->Nh;
c->data[c->msgIndex++] = c->Nl;
return 1;
}
static int SHA1_Update(SHA1_Context *c, const unsigned char *chBuff, unsigned int n)
{
unsigned int lastBytes = 0;
unsigned int temp = 0;
unsigned int i = 0;
unsigned int tempBits = 0;
if (!c || !chBuff || !n || c->isTooMang)
{
return -1;
}
if (n > strlen((char *)chBuff))
{
n = strlen((char *)chBuff);
}
if (c->FlagInWord > 0)
{
temp = (unsigned int)(4 - c->FlagInWord) < n ? (unsigned int)(4 - c->FlagInWord) : n;
for (i = temp; i > 0; --i)
{
c->data[c->msgIndex] |= ((unsigned long)chBuff[temp - i]) << (3 - c->FlagInWord++) * 8;
}
tempBits = c->Nl;
c->Nl += 8 * temp;
if (tempBits > c->Nl)
{
++(c->Nh);
if (c->Nh == 0)
{
c->isTooMang = 1;
}
}
if ((c->FlagInWord) / 4 > 0)
{
++(c->msgIndex);
}
c->FlagInWord = c->FlagInWord % 4;
if (c->msgIndex == 16)
{
SHA1_One(c);
}
}
chBuff += temp;
n -= temp;
if (n >= 4)
{
for (i = 0; i <= n - 4; i += 4)
{
c->data[c->msgIndex] |= ((unsigned long)chBuff[i]) << 24;
c->data[c->msgIndex] |= ((unsigned long)chBuff[i + 1]) << 16;
c->data[c->msgIndex] |= ((unsigned long)chBuff[i + 2]) << 8;
c->data[c->msgIndex] |= ((unsigned long)chBuff[i + 3]);
++(c->msgIndex);
tempBits = c->Nl;
c->Nl += 32;
if (tempBits > c->Nl)
{
c->Nh++;
if (c->Nh == 0)
{
c->isTooMang = 1;
}
}
if (c->msgIndex == 16)
{
SHA1_One(c);
}
}
}
if (n > 0 && n % 4 != 0)
{
lastBytes = n - i;
switch (lastBytes)
{
case 3:
c->data[c->msgIndex] |= ((unsigned long)chBuff[i + 2]) << 8;
case 2:
c->data[c->msgIndex] |= ((unsigned long)chBuff[i + 1]) << 16;
case 1:
c->data[c->msgIndex] |= ((unsigned long)chBuff[i]) << 24;
}
c->FlagInWord = lastBytes;
tempBits = c->Nl;
c->Nl += 8 * lastBytes;
if (tempBits > c->Nl)
{
++(c->Nh);
if (0 == c->Nh)
{
c->isTooMang = 1;
}
}
if (16 == c->msgIndex)
{
SHA1_One(c);
}
}
return 1;
}
static int SHA1_Final(SHA1_Context *c, unsigned char * md)
{
int i = 0;
if ((NULL == md) || (NULL == c) || (c->isTooMang))
{
return -1;
}
SHA1_PadMessage(c);
SHA1_One(c);
for (i = 0; i < 5; ++i)
{
md[4 * i] = (unsigned char)((c->h[i] & 0xff000000) >> 24);
md[4 * i + 1] = (unsigned char)((c->h[i] & 0x00ff0000) >> 16);
md[4 * i + 2] = (unsigned char)((c->h[i] & 0x0000ff00) >> 8);
md[4 * i + 3] = (unsigned char)(c->h[i] & 0x000000ff);
}
return 1;
}
int SHA1_String(const unsigned char* inputString, unsigned long len, unsigned char* pOutSHA1Buf)
{
int rt = -1;
SHA1_Context c;
if ((NULL == inputString) || (NULL == pOutSHA1Buf))
{
return -1;
}
rt = SHA1_Init(&c);
if (-1 == rt)
{
return -1;
}
SHA1_Update(&c, inputString, len);
SHA1_Final(&c, pOutSHA1Buf);
SHA1_Clear_data(&c);
return 1;
}
int SHA1_String_Compare(const unsigned char* inputString, unsigned long len, const unsigned char* pOutSHA1Buf)
{
unsigned char buff[SHA1_SIZE_BYTE] = { 0 };
int rt = -1;
int i = 0;
rt = SHA1_String(inputString, len, buff);
if (1 == rt)
{
for (i = 0; i < SHA1_SIZE_BYTE; ++i)
{
if (buff[i] != pOutSHA1Buf[i])
{
return -1;
}
}
return 1;
}
else
{
return -1;
}
}
int SHA1_File(const char* filePath, unsigned char *buff)
{
int rt = -1;
FILE *file = NULL;
SHA1_Context context;
int len = 0;
unsigned char buffer[0x0400] = { 0 };
file = fopen(filePath, "rb");
if (NULL == file)
{
return -1;
}
else
{
rt = SHA1_Init(&context);
if (-1 == rt)
{
fclose(file);
return -1;
}
while (len = fread(buffer, 1, 1024, file))
{
rt = SHA1_Update(&context, buffer, len);
if (-1 == rt)
{
fclose(file);
return -1;
}
}
rt = SHA1_Final(&context, buff);
fclose(file);
return rt;
}
}
int SHA1_File_Compare(const char* filePathA, const char *filePathB)
{
char hashValueA[SHA1_SIZE_BYTE] = { 0 };
char hashValueB[SHA1_SIZE_BYTE] = { 1 };
int rt = -1;
int i = 0;
if ((NULL == filePathA) || (NULL == filePathB))
{
return -1;
}
rt = SHA1_File(filePathA, (unsigned char *)hashValueA);
if (1 == rt)
{
rt = SHA1_File(filePathB, (unsigned char *)hashValueB);
if (1 == rt)
{
for (i = 0; i < SHA1_SIZE_BYTE; ++i)
{
if (hashValueA[i] != hashValueB[i])
{
return -1;
}
}
return 1;
}
else
{
return -1;
}
}
else
{
return -1;
}
}
/**
* @file SHA1.h
* @brief SHA-1 coden take from gnupg 1.3.92.
* @author Don
* @date 2011-7-28 22:49:55
* @version
* copyright:
* email: [email protected]
* company:
* All rights reserved.
* modification:
* Write modifications here.
*/
#ifndef _USER_SHA1_H
#define _USER_SHA1_H
#include
#include
#define SHA1_SIZE_BYTE 20
/**
* @brief SHA1_String
*
* Detailed description.
* @param[in] inputString 要进行处理的无符号字符串指针
* @param[in] len 要处理的信息长度,n<= strlen(p);
* @param[out] pOutSHA1Buf 输出摘要信息,长度为20的 unsigned char ,共160 bits
* @return int
*/
int SHA1_String(const unsigned char* inputString, unsigned long len, unsigned char* pOutSHA1Buf);
/**
* @brief SHA1_String_Compare
*
* Detailed description.
* @param[in] inputString
* @param[in] len
* @param[in] pOutSHA1Buf
* @return int
*/
int SHA1_String_Compare(const unsigned char* inputString, unsigned long len, const unsigned char* pOutSHA1Buf);
/**
* @brief SHA1_File
*
* Detailed description.
* @param[in] filePath 要计算MD5的文件的路径
* @param[in] buff 输出的MD5值,该缓冲区大小应为MD5_SIZE_BYTE
* @return int
*/
int SHA1_File(const char* filePath, unsigned char* buff);
/**
* @brief SHA1_File_Compare
*
* Detailed description.
* @param[in] filePathA 要对比MD5的第一个文件的路径
* @param[in] filePathB 要对比MD5的第二个文件的路径
* @return int
*/
int SHA1_File_Compare(const char* filePathA, const char* filePathB);
#endif /**< _USER_SHA1_H */
//BASE64.c
#include "StdAfx.h"
#include "base64.h"
#include
#include
// 全局常量定义
const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char padding_char = '=';
/*编码代码
* const unsigned char * sourcedata, 源数组
* char * base64 ,码字保存
*/
int base64_encode(const unsigned char * sourcedata, unsigned int datalength, char * base64)
{
int i = 0, j = 0;
unsigned char trans_index = 0; // 索引是8位,但是高两位都为0
//const int datalength = strlen((const char*)sourcedata);
for (; i < datalength; i += 3){
// 每三个一组,进行编码
// 要编码的数字的第一个
trans_index = ((sourcedata[i] >> 2) & 0x3f);
base64[j++] = base64char[(int)trans_index];
// 第二个
trans_index = ((sourcedata[i] << 4) & 0x30);
if (i + 1 < datalength){
trans_index |= ((sourcedata[i + 1] >> 4) & 0x0f);
base64[j++] = base64char[(int)trans_index];
}
else{
base64[j++] = base64char[(int)trans_index];
base64[j++] = padding_char;
base64[j++] = padding_char;
break; // 超出总长度,可以直接break
}
// 第三个
trans_index = ((sourcedata[i + 1] << 2) & 0x3c);
if (i + 2 < datalength){ // 有的话需要编码2个
trans_index |= ((sourcedata[i + 2] >> 6) & 0x03);
base64[j++] = base64char[(int)trans_index];
trans_index = sourcedata[i + 2] & 0x3f;
base64[j++] = base64char[(int)trans_index];
}
else{
base64[j++] = base64char[(int)trans_index];
base64[j++] = padding_char;
break;
}
}
base64[j] = '\0';
return 0;
}
/** 在字符串中查询特定字符位置索引
* const char *str ,字符串
* char c,要查找的字符
*/
inline int num_strchr(const char *str, char c) //
{
const char *pindex = strchr(str, c);
if (NULL == pindex){
return -1;
}
return pindex - str;
}
/* 解码
* const char * base64 码字
* unsigned char * dedata, 解码恢复的数据
*/
int base64_decode(const char * base64, unsigned char * dedata)
{
int i = 0, j = 0;
int trans[4] = { 0, 0, 0, 0 };
for (; base64[i] != '\0'; i += 4){
// 每四个一组,译码成三个字符
trans[0] = num_strchr(base64char, base64[i]);
trans[1] = num_strchr(base64char, base64[i + 1]);
// 1/3
dedata[j++] = ((trans[0] << 2) & 0xfc) | ((trans[1] >> 4) & 0x03);
if (base64[i + 2] == '='){
continue;
}
else{
trans[2] = num_strchr(base64char, base64[i + 2]);
}
// 2/3
dedata[j++] = ((trans[1] << 4) & 0xf0) | ((trans[2] >> 2) & 0x0f);
if (base64[i + 3] == '='){
continue;
}
else{
trans[3] = num_strchr(base64char, base64[i + 3]);
}
// 3/3
dedata[j++] = ((trans[2] << 6) & 0xc0) | (trans[3] & 0x3f);
}
dedata[j] = '\0';
return 0;
}
//BASE64.h
#ifndef base64_h
#define base64_h
int base64_encode(const unsigned char * sourcedata, unsigned int datalength, char * base64);
#endif /* base64_h */
//测试
IHttpServer *mHttpServer;
HttpServerListernet *mHttpServerListernet;
this->mHttpServerListernet = new HttpServerListernet();
this->mHttpServer = HP_Create_HttpServer(this->mHttpServerListernet);
if (this->mHttpServer != nullptr)
{
if (this->mHttpServer->Start(L"0.0.0.0", 4567) == FALSE)
{
int error = this->mHttpServer->GetLastError();
System::Windows::Forms::MessageBox::Show("初始化web服务器失败,错误代码:" + error, "错误", System::Windows::Forms::MessageBoxButtons::OK,
System::Windows::Forms::MessageBoxIcon::Error);
}
}
else
{
System::Windows::Forms::MessageBox::Show("初始化 mHttpServer 失败!", "错误", System::Windows::Forms::MessageBoxButtons::OK,
System::Windows::Forms::MessageBoxIcon::Error);
}
html_base_path:web网页目录,默认打开里面的index.html文件