【问题标题】:Issues spawning a casablanca http_listener in a win32 service (C++)在 win32 服务 (C++) 中生成 casablanca http_listener 的问题
【发布时间】:2020-05-13 11:55:04
【问题描述】:

由于某种原因,我无法在我的 Windows 服务主线程中启动我的侦听器,代码编译时没有警告并且我没有收到任何链接错误,cpprestsdk DLL 由进程正确加载(使用 procmon 验证)但是,听众不是在“听”:-)。该服务作为 NT AUTHORITY\SYSTEM 运行。在 win32 服务(x64 架构)中运行它是否有任何限制:

DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
    //
    //  Periodically check if the service has been requested to stop
    while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
    {
        /*
        * Perform main service function here
        */

        webserver();
    }

    return ERROR_SUCCESS;
}

这里是 webserver() 的实现:

#include <iostream>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>
#include <map>
#include <set>
#include <string>

using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;
using namespace std;

void handle_GET(http_request message)
{
    message.reply(status_codes::OK, "<html><body><h1>Hello World !</h1></body></html>", u8"text/html");
    return;
}

void webserver()
{
    http_listener listener(L"http://127.0.0.1/api");
    listener.support(methods::GET, handle_GET);
    listener.open().wait();
}

如果我简单地将它编译为普通的可执行文件并从 main() 运行它,这个函数就可以工作...

任何想法为什么我会出现这种奇怪的行为?

PS:即使监听器不工作,服务也能正确启动和停止。我正在使用这个框架 Windows 服务模板 (Windows Service Template)

我正在使用 Microsoft Visual Studio 2017 编译所有内容。

编辑:通过禁用防火墙并以管理员权限运行 netstat,该服务似乎正在侦听 127.0.0.1 地址上的端口 80,但是我仍然没有收到 HTTP 响应并且运行“netstat -an | findstr 80”时,监听端口似乎会打开和关闭:

Screenshot

【问题讨论】:

  • 您在哪个服务帐户下运行?有些帐户没有网络访问权限。
  • 嗨,它正在使用 SYSTEM 帐户运行。
  • 有趣,但在我的情况下,它不是防火墙,因为当我运行“netstat -a”并且我试图通过环回地址(127.0.0.1)连接时,端口甚至没有绑定像这样:“wget 127.0.0.1:80/api
  • 我的错误,如果我禁用防火墙和杀毒软件,端口正在监听...但是,http 请求没有得到任何响应。

标签: c++ c winapi service casablanca


【解决方案1】:

好的,我最终这样做了,这似乎“解决”了这个问题:

#include <iostream>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>
#include <map>
#include <set>
#include <string>
#include <Windows.h>

using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;
using namespace std;

void handle_GET(http_request message)
{
    message.reply(status_codes::OK, "<html><body><h1>Hello World !</h1></body></html>", u8"text/html");
    return;
}

void webserver()
{
    http_listener listener(L"http://127.0.0.1/api");
    listener.support(methods::GET, handle_GET);
    listener.open().wait();
    ::Sleep(1000000000000000000);
}

但我认为这很讨厌,我怀疑它只是根据睡眠时间来回摆动...

#include "api.h"
#include <thread>
#include "ServiceWorkerThread.h"

DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
    //
    //  Periodically check if the service has been requested to stop
    while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
    {
        /*
        * Perform main service function here
        */
        webserver();
    }

    return ERROR_SUCCESS;
}

关于如何做这个清洁剂的任何建议?

解决方案:我最终像这样更改代码:

#include <iostream>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>
#include <map>
#include <set>
#include <string>
#include <Windows.h>
#include "ServiceWorkerThread.h"

using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;
using namespace std;

void handle_GET(http_request message)
{
    message.reply(status_codes::OK, "<html><body><h1>Hello World !</h1></body></html>", u8"text/html");
    return;
}

long webserver()
{
    http_listener listener(L"http://127.0.0.1/api");
    listener.support(methods::GET, handle_GET);
    listener.open().wait();
    //
//  Periodically check if the service has been requested to stop
    while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
    {
        /*
        * Perform main service function here
        */
    }

    return ERROR_SUCCESS;
}

#include "api.h"
#include <thread>
#include "ServiceWorkerThread.h"

DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
    long ret = webserver();
    return ret;
}

除了在 Windows 防火墙中例外...

【讨论】: