2409atl,atl网络服务器

embedded/2025/1/15 17:48:27/

原文

介绍

首先,回顾一下为简化ATLServer开发而添加的一些新类.需要时可随时使用这些类,而不仅是用来ATLServer开发.

密码学(CCryptProv,CCryptKey,CCryptKeyedHash等):

加密引用(MSDN)

哈希:

CCryptProv prov;
prov.Initialize();
char rand[256];
memset(rand, 0, sizeof(rand));
//生成加密随机字节
HRESULT hr = prov.GenRandom(sizeof(rand), (BYTE*)rand);
if(hr != S_OK)return 0;
//`哈希`,`待办`:输入用户的密码.永远不要像这样硬编码!
const char* szPassword = "#$%^!SDD%$^&%^&~";
char Hash1st[256]; DWORD dwSize=256;
char Hash2nd[256];
memset(Hash1st, 0, sizeof(Hash1st));
memset(Hash2nd, 0, sizeof(Hash2nd));
CCryptKeyedHash hash;
//使用`SHA-1`或其他方法,如`MD5,HMAC`等
hash.Initialize(prov, CALG_SHA1, CCryptKey::EmptyKey, 0);
//加数据到`哈希`
hr = hash.AddString(szPassword);
if(hr != S_OK)return 0;
//取哈希值
hr = hash.GetValue((BYTE*)Hash1st, &dwSize);
if(hr != S_OK)return 0;
hash.Destroy();
//现在可随时检查哈希值与原值
hash.Initialize(prov, CALG_SHA1, CCryptKey::EmptyKey, 0);
//添加数据到`哈希`
hr = hash.AddString(szPassword);
if(hr != S_OK)return 0;
//取哈希值
hr = hash.GetValue((BYTE*)Hash2nd, &dwSize);
if(hr != S_OK)return 0;
//哈希值应匹配
if(memcmp(Hash1st, Hash2nd, sizeof(Hash1st)) == 0)ATLTRACE("\npassword matched.\n\n");

加密:

const int ENCRYPT_BLOCK_SIZE = 64;//因为用了使用`分组密码模式`的`TripleDES`,因此数据大小`必须是块大小的倍数`(`TripleDes`为`8`)
DWORD dwBlockLen = 2000 - 1000 % ENCRYPT_BLOCK_SIZE;
ATLASSERT((dwBlockLen%8)==0);
CHeapPtr<BYTE> buff;
buff.Allocate(dwBlockLen);
CCryptProv prov;
//需要`MS_ENHANCED_PROV`或`MS_STRONG_PROV`来取`TripleDES`算法
HRESULT hr = prov.Initialize(PROV_RSA_FULL, NULL, MS_STRONG_PROV);//`待办`:使用一些数据创建叫`testpln.txt`的文件,如加密文件使用`TripleDES`和基于密码的代码
{CCryptDerivedKey derKey;//对`要加密的文件`,使用`md5`哈希来`哈希`密码,一般你会使用`SHA`,这只是为了展示如何需要,可轻松使用`md5`.CCryptMD5Hash md5;hr = md5.Initialize(prov);//哈希文件密码md5.AddString(szPassword);//初化键以使用基于`TripleDES`和基于`md5`的密码哈希hr = derKey.Initialize(prov,md5,CALG_3DES);//对`AES`为`16`,对`3DES`为8BYTE iv[8];//生成加密强度`高随机字节`hr = prov.GenRandom(8, iv);//按`IV`设置上述字节hr = derKey.SetIV(iv);//按`CBC`设置`模式`hr = derKey.SetMode(CRYPT_MODE_CBC);//设置填充hr = derKey.SetPadding(PKCS5_PADDING);FILE* pFilePl = fopen("testpln.txt", "rb"); //原文件if(pFilePl == NULL)return 0;FILE* pFileEn = fopen("testenc.txt", "wb"); //待加密文件DWORD dwEncLen = 0;DWORD dwOrigBlockLen = dwBlockLen;while(!feof(pFilePl)){DWORD nRead = fread(buff, 1, dwBlockLen, pFilePl); //读取纯数据DWORD nEnc = nRead;//加密数据,数据和大小返回给我们hr = derKey.Encrypt(feof(pFilePl), (BYTE*)buff, &nEnc, dwBlockLen);if(hr == HRESULT_FROM_WIN32(ERROR_MORE_DATA)) //错误,缓冲大小不足{buff.Reallocate(nEnc);dwBlockLen = nEnc;hr = derKey.Encrypt(feof(pFilePl),(BYTE*)buff,&nRead,dwBlockLen);nEnc = nRead;}if(hr != S_OK)break;fwrite(buff, 1, nEnc, pFileEn); //写加密数据}fclose(pFileEn);fclose(pFilePl);//调整回来`缓冲大小`,以防更改它dwBlockLen = dwOrigBlockLen;buff.Reallocate(dwBlockLen);
}
//使用`TripleDES`,并基于密码,解密相同文件
{CCryptDerivedKey derKey;CCryptMD5Hash md5;hr = md5.Initialize(prov);//文件密码md5.AddString(szPassword);//基于`md5`的密码哈希,初化键以使用基于`TripleDES`hr = derKey.Initialize(prov,md5,CALG_3DES);//如前设置`IV`,`模式`,`填充`FILE* pFileEn = fopen("testenc.txt", "rb"); //加密文件FILE* pFileDec = fopen("testdec.txt", "wb");//要解密的文件DWORD dwEncLen = 0;while(!feof(pFileEn)){//读取加密数据DWORD nRead = fread(buff, 1, dwBlockLen, pFileEn);//解密数据,给我们返回数据和大小hr = derKey.Decrypt(feof(pFileEn), buff, &nRead);if(hr != S_OK)break;fwrite(buff, 1, nRead, pFileDec); //写入解密数据}fclose(pFileDec);fclose(pFileEn);
}

正则式:

CAtlRegExp<> regexp;
CAtlREMatchContext<> mc;
//匹配以`多个数字开头`,有`短划线`并以`多个数字结尾`的行
if(regexp.Parse("^\\d+-\\d+$") == REPARSE_ERROR_OK)
{const char* szNumDashNum="5663-4662";if(regexp.Match(szNumDashNum, &mc)){ATLTRACE("Matched");}
}

支持发送SMTP电子消息:

CoInitialize(0);
{CSMTPConnection conn;conn.Connect("SMTP Server Address");CMimeMessage msg;msg.SetSender(_T("sender@address"));msg.AddRecipient(_T("recepient@address"));msg.SetPriority(ATL_MIME_HIGH_PRIORITY);//`msg.AttachFile(_T("`文件名`"));`msg.AddText(_T("message text"));msg.SetSubject(_T("Subject line"));conn.SendMessage(msg);
}
CoUninitialize();

编码:

BEncode,Base64Encode,UUEncode,QEncode,QPEncode,AtlHexEncode.

CString sSource = "some string";
int nDestLen = Base64EncodeGetRequiredLength(sSource.GetLength());
CString str64;
Base64Encode((const BYTE*)(LPCSTR)sSource, sSource.GetLength(),str64.GetBuffer(nDestLen),&nDestLen);
str64.ReleaseBuffer(nDestLen);
cout<<(LPCSTR)str64;
int nDecLen = Base64DecodeGetRequiredLength(nDestLen);
CString strOrig;
Base64Decode(str64, str64.GetLength(), (BYTE*)strOrig.GetBuffer(nDecLen),&nDecLen);
strOrig.ReleaseBuffer(nDecLen);
cout<<(LPCSTR)strOrig;

生成HTML:

HTML Generation Reference(MSDN)
CHtmlGen html;
CWriteStreamOnCString stream;
html.Initialize(&stream);
html.html();
html.head();
html.title(_T("Sample Page"));
html.headEnd();
html.body(_T("Gray"));
html.WriteRaw(_T("Using ATL7!"));
html.bodyEnd();
html.htmlEnd();
cout<<(LPCTSTR)stream.m_str;

HTTP客户:

class CHttpClientWithCookie : public CAtlHttpClient
{template<>void OnSetCookie(LPCTSTR cookie){std::cout<<"Got Cookie from server: "<<std::endl<<cookie<<std::endl;return;}
};
{
CHttpClientWithCookie client;
//客户.浏览分块`()`
client.Navigate("http://www.microsoft.com");
const char* pszBody = (const char*)client.GetBody();
CString sRawHdr; DWORD dwLen;
client.GetRawResponseHeader(0, &dwLen);
client.GetRawResponseHeader((BYTE*)sRawHdr.GetBufferSetLength(dwLen), &dwLen);
std::cout<<"Raw Response Header: "<<std::endl<<(LPCTSTR)sRawHdr;
}

还有许多其他其他助手类和更具体的助手类,来处理网络应用或网络服务开发.

调试:

ISAPI过滤/扩展概述:

ISAPI代表互联网服务器应用编程接口.ISAPI编程分为过滤器扩展.两者都是带特定导出函数DLL.

ISAPI过滤随IIS一起加载,并在内存中保留,直到HTTPWeb服务关闭.ISAPI扩展按需加载,并为网络应用提供扩展功能.

ISAPI过滤,对检查/过滤IIS下的传入和传出HTTP请求(如,实现自定义认证,加密,压缩,记录日志等)很有用.
ISAPI扩展对开发动态网页,和按URL引用工作非常有用.

ATL7下没有ISAPI过滤的类.ATLServerDLL缓存,文件缓存,页缓存,内存缓存,数据源缓存,线程池,使用基于网络或基于网络服务的接口远程管理,预定义性能计数器,会话支持等形式提供对ISAPI扩展的支持.

可见,这是大量功能/服务.此外,可轻松地在现有服务添加你自己的服务.

网络应用

ATL7Web应用是ISAPI扩展和处理器DLL(或两者可组合成一个DLL)的组合,来创建动态网页.

ISAPI扩展是一个导出三个函数DLL:HttpExtensionProc,GetExtensionVersion,TerminateExtension.

处理器DLLWeb应用DLL还为ATL导出三个预定义函数:InitializeAtlHandlers,GetAtlHandlerByName,UninitializeAtlHandlers.

ATL7Web应用基于模板构建.一个一般有.srf扩展名的文本文件,在ISAPI扩展名的虚目录中,且可有混合静态超文本动态/运行时可替换标签的内容.

GetExtensionVersion中,ATL初化它使用的堆,预定义的性能显示器,工作线程,线程池,dllcache,页缓存和模板缓存.
TerminateExtension相反.

所有工作的主要函数HttpExtensionProc.负责实现它的类CIsapiExtension.CIsapiExtension::HttpExtensionProc传入请求排队到I/O完成端口.

由在(CThreadPool)线程池中运行的工作线程检查此完成端口.所有这些工作线程,只是在上述完成端口(请求从HttpExtensionProc排队)上用GetQueuedCompletionStatus阻止.

默认,中有2个启动线程(由CThreadPool实现的ATLS_DEFAULT_THREADSPERPROCIThreadPoolConfig控制).

因此,当这些工作者线程中的可以成功地从端口分离完成请求时,它们执行该请求.

请求表明处理模板文件,首先在页缓存中查找整个处理的页,通过覆盖CachePage()方法并从CRequestHandlerT继承类返回来控制.

如果找到,则把整个页文件简单转移地给用户,则完成了.否则,在缓存模板查找模板文件.

如果不在缓存中,则从磁盘读取(.srf)文件,解析处理器DLL标签,如果尚未在DLL缓存中,则加载DLL.

调用处理器DLL入口,即InitializeAtlHandlers,然后通过GetAtlHandlerByName找到处理请求处理器类.然后,从模板文件解析所有剩余的替换标签.

模板文件已渲染的,即,如果在CRequestHandlerT继承类中,使用属性REPLACEMENT_METHOD_MAP,对表示方法所有标签,可通过tag_name定义的GetAttrReplacementMethodMap找到处理器类方法的地址.

然后调用方法并生成网页的动态内容.再返回生成内容给用户.最好在调试器查看事件序列,查看它的内部工作原理很有趣.

通过在HttpExtensionProc放置断点,单步ATL代码,然后单步到PostQueuedCompletionStatus.在GetQueuedCompletionStatus循环中,放置另一个断点.

现在,可按F5,并按如下步骤操作.

1,向导生成的代码(当你选择DataSourceCache时,也可自己干,但这可作为示例)还为每线程服务生成自定义的CIsapiWorker继承类.

2,这是为线程池中的每个线程创建的类.这允许为每线程添加自己的方法和数据成员.

3,即不需要同步,且请求处理器类,可通过调用IIsapiExtension::GetThreadWorker来取此每线程工作者的指针,链接也提供了使用它的示例.

ATLServer还提供了多种方法来控制和配置网络应用.它为远程控制线程池,SRF文件缓存和网络应用DLL缓存提供了默认实现.

你只需为你想要通过HTMLWeb接口或网络服务公开服务,定义适当的符号,限制特定用户等,然后你就可免费取得完整实现!

可按扩展管理服务描述步骤逐步操作!

扩展管理XMLWeb服务客户

创建新项目选择服务:缓存,文件缓存,数据源缓存,浏览器函数,会话服务,及帧提供的服务:DllCache,StencilCache,ThreadPoolConfigAtlMemMgr,都通过CIsapiExtension继承类实现IServiceProvider::QueryService公开.

还可在运行时通过IIsapiExtension::AddService和稍后的QueryService为它们添加自己的服务.把第一组服务的代码添加到请求处理器类中,并注释掉.

只需取消注释并用来满足你的需求.

此外,还有预定义的ISAPI性能计数器可用.添加你自己的性能计数器很容易.有一个此内容的简单示例,并在ATLServer教程的收集统计节下添加自定义服务.

网服

ATLWeb服务支持也可按ISAPI扩展实现.可用该向导,也可手动.创建简单的Win32DLL项目.

添加def文件以导出3个ISAPI扩展函数.然后,按最简单,使用ATL7实现的网络服务如下:

//`websvc.h`
#pragma once
namespace ATL7WebService
{[export]struct S{int n;double d;};[uuid("86C903DD-4D9F-4928A3B5AE242EA86D7A")]__interface IWebSvc{HRESULT GetString([out,retval] BSTR* pVal);HRESULT GetData([out, retval] ATLSOAP_BLOB* pBlob);HRESULT GetStruct([out, retval] S* pVal);//等};[request_handler(name="Default", sdl="WSDL")][soap_handler(name="WebSvc", namespace="urn:ATL7WebService")]class CWebSvc : public IWebSvc{public:[soap_method]HRESULT GetString(/*`[out,retval]`*/ BSTR* pVal){CComBSTR strOut("Some String");*pVal = strOut.Detach();return S_OK;}[soap_method]HRESULT GetData(/*[出,返回值]*/ ATLSOAP_BLOB* pBlob){IAtlMemMgr* pMem = GetMemMgr();pBlob->size = 1000;pBlob->data = (unsigned char*)pMem->Allocate(pBlob->size);memset(pBlob->data, 'a', pBlob->size);return S_OK;}[soap_method]HRESULT GetStruct(/*[出,返回值]*/ S* pVal){pVal->n = 10;pVal->d = 1.1;return S_OK;}//等};
}

服务器:

//`websvc.cpp`
#define _WIN32_WINNT 0x0403
//需要属性
#define _ATL_ATTRIBUTES
//对此简单项目,不用`COM`
#define _ATL_NO_COM_SUPPORT
#include <atlisapi.h>
#include <atlsoap.h>
#include "websvc.h"
[ module(name="WebSvc", type="dll") ]
//不需要生成`.idl,.tlb`等文件
[ emitidl(restricted) ]
CIsapiExtension<> theExtension;
extern "C" DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB)
{  return theExtension.HttpExtensionProc(lpECB); }
extern "C" BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO* pVer)
{  return theExtension.GetExtensionVersion(pVer); }
extern "C" BOOL WINAPI TerminateExtension(DWORD dwFlags)
{ return theExtension.TerminateExtension(dwFlags); }

网络部署,使用VC++.NET项目属性,并在应用映射下添加dll扩展,或在IIS创建虚目录,并手动注册应用映射.

之后,你可在网络浏览器中访问网络服务的WSDL,如下http://localhost/websvc/WebSvc.dllHandler=WSDL,
WebSvc.dll网络服务的实现,WSDL是你在request_handler中,对sql参数指定的编译器生成的处理器.

现在,再次访问它时,与上一节中的网络应用中一样,IIS会调用HttpExtensionProc.它会转发给CIsapiExtension.

CIsapiExtension会在I/O完成端口上排队请求.其中一个工作者线程会分离请求.然后,加载处理器DLL(websvc.dll).

会初化处理器.它的作用是,取通过网络服务类公开的所有函数,以在WSDL写入它们的信息.ATL已有为网络服务生成WSDL的模板.

可在atlspriv.h(const char*consts_szAtlsWSDLSrf)中找到它.你会看到它是一个适合Stencil处理的(带可替换的标签)简单模板文本.

因此,此串是通过CStencil::LoadFromString加载的,且会解析和替换/渲染所有标签.

现在,此WSDL输出可用来生成网络服务的客户.通过为.NET客户手动运行wsdl.exe,或运行ATL7提供的名为sproxy.exe的工具来生成代理客户文件,你可用VS.NET内置支持来添加网络服务.

如:sproxy/out:client.h http://localhost/websvc/WebSvc.dllHandler=WSDL

如果使用sproxy.exe,则生成的文件网络服务按C++类很好包装公开的方法.要使用它,只需在你的项目中,包含生成的文件(如client.h):

//`client.cpp`
#include <iostream>
#include "client.h"
int main()
{CoInitialize(NULL);{WebSvc::CWebSvc svc;CComBSTR str;if(svc.GetString(&str.m_str) == S_OK){std::wcout<<str.m_str<<std::endl;ATLSOAP_BLOB blob;if(svc.GetData(&blob) == S_OK){std::cout<<"blob of size: "<<blob.size<<std::endl;std::cout<<blob.data[0]<<blob.data<blob.size-1><<std::endl;IAtlMemMgr* pMem = svc.GetMemMgr();pMem->Free(blob.data);WebSvc::S s;svc.GetStruct(&s);}}}CoUninitialize();return 0;
}

如果要使用窗口整合认证或基本认证,可用CNTLMAuthObject/CBasicAuthObject(CSoapSocketClientT相关):

CoInitialize(NULL);
{//默认,使用`CSoapSocketClientT`WebSvc::CWebSvc svc;//此代码与`CSoapSocketClientT`相关CAtlHttpClient& httpClient = svc.m_socket;CNTLMAuthObject authUser;httpClient.AddAuthObj(_T("NTLM"), &authUser);httpClient.NegotiateAuth(true);CComBSTR str;if(svc.GetString(&str.m_str) == S_OK){//等}
}
CoUninitialize();

如果要使用HTTPS连接,可查看安全SOAP示例.
此外,还可选择使用预定义的类通信,如CSoapSocketClientT(默认),CSoapWininetClient,CSoapMSXMLInetClient:

WebSvc::CWebSvcT<CSoapWininetClient> svc;
CComBSTR str;
if(svc.GetString(&str.m_str) == S_OK)
{//等
}

http://www.ppmy.cn/embedded/108430.html

相关文章

认识git和git的基本使用,本地仓库,远程仓库和克隆远程仓库

本地仓库 #安装git https://git-scm.com/download/win #git是什么&#xff1f;有什么用&#xff1f; git相当于一个版本控制系统&#xff0c;版本控制是一种记录一个或若干文件内容变化&#xff0c;以便将来查阅特定版本修订情况的系统。 作用: 记录&#xff08;项目&#…

主窗口的设计与开发(二)

主窗口的设计与开发&#xff08;二&#xff09; 前言 在上一集当中&#xff0c;我们完成了主窗口的初始化&#xff0c;主窗口包括了左中右三个区域。我们还完成了对左窗口的初始化&#xff0c;左窗口包括了用户头像、会话标签页按钮、好友标签页按钮以及好友申请标签页按钮。对…

【React】Vite 构建 React

项目搭建 vite 官网&#xff1a;Vite 跟着文档走即可&#xff0c;选择 react &#xff0c;然后 ts swc。 着重说一下 package-lock.json 这个文件有两个作用&#xff1a; 锁版本号&#xff08;保证项目在不同人手里安装的依赖都是相同的&#xff0c;解决版本冲突的问题&am…

深度学习 目标分类 目标检测 多目标跟踪 基础 进阶

深度学习 目标分类 目标检测 多目标跟踪 基础 进阶 flyfish 深度学习基础 文章名称链接深度学习基础 - 直线链接深度学习基础 - 梯度垂直于等高线的切线链接深度学习基础 - 向量投影链接一阶优化算法&#xff08;如梯度下降&#xff09;和二阶优化算法&#xff08;如牛顿法&…

端口安全老化细节

我们都知道port-security aging-time命令用来配置端口安全动态MAC地址的老化时间&#xff0c;但是后面还可以加上类型&#xff1a; [SW1-GigabitEthernet0/0/1]port-security aging-time 5 type absolute Absolute time 绝对老化 inactivity Inactivity time相对老化 …

Java stream使用与执行原理

stream简介 Stream: A sequence of elements supporting sequential and parallel aggregate operations stream为sequential即单线程串行操作&#xff0c;parallelStream支持并行操作&#xff0c;本文只讨论sequential的stream。 stream常用操作 Datastatic class Course {pr…

固态硬盘装系统有必要分区吗?

前言 现在的新电脑有哪一台是不使用固态硬盘的呢&#xff1f;这个好像很少很少了…… 有个朋友买了一台新的笔记本电脑&#xff0c;开机之后&#xff0c;电脑只有一个分区&#xff08;系统C盘500GB&#xff09;。这时候她想要给笔记本分区…… 这个真的有必要分区吗&#xf…

C语言从头学54——学习头文件assert.h、ctype.h

本文介绍头文件assert.h、ctype.h中定义的宏或函数&#xff0c;若使用下面这些宏或函数&#xff0c;需要包含相应的头文件。 1、assert() 断言宏 assert 功能是在运行时检查指定条件&#xff0c;如果不符合条件报错终止运行。 使用格式&#xff1a;assert (条件…