【发布时间】:2022-11-17 07:32:57
【问题描述】:
我希望通过 IIS 中的本机模块实现本机 websocket 处理程序。我发现围绕它的文档非常模糊并且缺少很多细节。
我已经创建了一个 IIS Native 模块 DLL,它正在运行。我可以保持简单,只返回一个带有 HTTP/200 响应的 hello world html 文件,一切都很好。
但是,我在尝试让它处理 websocket 连接时遇到了问题。微软的 IIS 博客网站 here 上有一篇博文描述了如何处理 websocket 连接。我遵循它并进行了测试,是的,连接是从网络浏览器打开的,但是我无法从本机模块中的套接字读取数据,并且连接经常在客户端出现错误关闭 - 在随机看起来的时间。
该模块的 OnBeginRequest 方法是:
REQUEST_NOTIFICATION_STATUS CKIIS::OnBeginRequest(IN IHttpContext* pHttpContext, IN IHttpEventProvider* pProvider) {
UNREFERENCED_PARAMETER(pProvider);
HRESULT hr;
// I've only placed this here so I can attach a debugger.
std::this_thread::sleep_for(std::chrono::seconds(10));
this->_context = pHttpContext;
IHttpResponse* pHttpResponse = pHttpContext->GetResponse();
if (pHttpResponse != NULL)
{
pHttpResponse->Clear();
pHttpResponse->SetStatus(101, "Switching Protocols");
pHttpResponse->SetHeader(
HttpHeaderUpgrade, "websocket",
(USHORT)strlen("websocket"), TRUE);
pHttpResponse->SetHeader(
HttpHeaderConnection, "Upgrade",
(USHORT)strlen("Upgrade"), TRUE);
DWORD cbSent = 0;
BOOL fCompletionExpected = false;
hr = pHttpResponse->Flush(false, true, &cbSent, &fCompletionExpected);
std::this_thread::sleep_for(std::chrono::seconds(10));
IHttpContext3* pHttpContext3;
HttpGetExtendedInterface(this->_server, pHttpContext, &pHttpContext3);
IWebSocketContext* cts = (IWebSocketContext*)pHttpContext3->GetNamedContextContainer()->GetNamedContext(L"websockets");
char buffer[1024 * 100];
DWORD sz = 1024 * 100;
BOOL utf;
BOOL finalfrag;
BOOL conclose;
DWORD clxc = 78;
BOOL expected;
// This method call returns E_NOTIMPL.
// The documentation does not even indicate this is an expected return of this.
HRESULT res = cts->ReadFragment(
&buffer,
&sz,
false,
&utf,
&finalfrag,
&conclose,
Compl,
&clxc,
&expected);
// Start a thread to read/write from the websocket.
this->_runner = thread(&CKIIS::RunWork, this);
// Tell IIS to keep the connection pending...
return RQ_NOTIFICATION_PENDING;
}
// Return processing to the pipeline.
return RQ_NOTIFICATION_CONTINUE;
}
void CKIIS::RunWork() {
IHttpContext3* pHttpContext3;
HttpGetExtendedInterface(this->_server, this->_context, &pHttpContext3);
IWebSocketContext* cts = (IWebSocketContext*)pHttpContext3->GetNamedContextContainer()->GetNamedContext(L"websockets");
for (;;) {
// Loop to read/write the socket...
// If I call cts->ReadFragment() or cts->WriteFragment() here
// the method will return E_NOTIMPL too.
/// Eventually break out of the loop.
}
try {
//this->_context->IndicateCompletion(RQ_NOTIFICATION_FINISH_REQUEST);
this->_context->PostCompletion(0);
}
catch(const std::exception& e){
const char* barf = e.what();
std::cout << e.what();
}
}
几个问题:
- 为什么 ReadFragment/WriteFragment 返回 E_NOTIMPL。在 OnBeginRequest 方法中,或者如果我尝试在它自己的线程中执行它。
- 这里使用新线程来处理对 websocket 的读/写是首选模式吗?像轮询数据这样的繁忙循环似乎很浪费,但是当客户端提供数据时,我看不到任何注册通知的方法
【问题讨论】:
-
你在说什么?我正在尝试利用IIS 的 websocket 模块,不是克隆。该接口完全针对我的用例公开。
标签: c++ winapi websocket iis-10