【问题标题】:Server-Sent Events using Poco::Net::HTTPRequestHandler使用 Poco::Net::HTTPRequestHandler 的服务器发送事件
【发布时间】:2013-03-24 17:28:15
【问题描述】:

我正在尝试使用服务器发送的事件将数据“流式传输”到 HTML5 页面。

本教程http://www.html5rocks.com/en/tutorials/eventsource/basics/ 对让客户端正常工作很有帮助。

但对于服务器端,我正在做类似于http://pocoproject.org/slides/200-Network.pdf 中的 HTTPServer 示例

html5rocks.com 教程为我提供了请求处理程序代码的以下想法:

void MyRequestHandler::handleRequest (HTTPServerRequest &req, HTTPServerResponse &resp)
{
    resp.setStatus(HTTPResponse::HTTP_OK);

    resp.add("Content-Type", "text/event-stream");
    resp.add("Cache-Control", "no-cache");

    ostream& out = resp.send();

    while (out.good())
    {
        out << "data: " << "some data" << "\n\n";
        out.flush();

        Poco::Thread::sleep(500)
    }
}

以及 HTML5 页面的源代码:

<!DOCTYPE html>
<html>
    <head>
            <title>HTLM5Application</title>
    </head>
    <body>
        <p id="demo">hello</p>
        <script>
            var msgCounter = 0;
            var source;
            var data;
            if(typeof(EventSource) !== "undefined")
            {
                source = new EventSource('/stream');
                document.getElementById("demo").innerHTML = "Event source created";
            }
            else
            {
                document.getElementById("demo").innerHTML = "Are you using IE ?";
            }

            source.addEventListener('message', function(e)
            {
                msgCounter++;
                document.getElementById("demo").innerHTML = "Message received (" + msgCounter + ") !<br/>"+ e.data;
            }, false);
        </script>
    </body>
</html>

好消息是,当打开 html 页面时,数据会流式传输,并且我会得到正确的输出(标签之间的文本会按预期更新。

问题是当我在浏览器中关闭页面时,POCO程序崩溃了,我在控制台中得到如下信息:

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

Process returned 3 (0x3)   execution time : 22.234 s
Press any key to continue.

(我用的是Code::Blocks,所以才会显示返回值和执行时间)

当我将 while() 循环放在 try{ }catch(...){} 之间时发生的事件,程序仍然会在没有进入 catch 的情况下崩溃(当我将整个 main() 的内容放在 try 之间时也会发生同样的情况/抓)

主程序只包含这些指令:

int main(int argc, char* argv[])
{
    MyServerApp myServer;
    myServer.run(argc, argv);

    return 0;
}

我想知道导致崩溃的原因以及如何修复它。

提前感谢您的帮助:)

【问题讨论】:

  • 嘿,你最终找到解决这个问题的方法了吗?我处于同样的情况,正在考虑在服务器套接字上使用反应器来手动关闭连接。
  • 当时,我在 Windows7 操作系统上进行开发。如果我没记错的话,这就是 try/catch 不起作用的原因。所以最终没有在该平台上使用服务器发送的事件。但是,我认为相同的代码(即带异常处理)在 Linux 上应该没问题。
  • 感谢您的回复。我现在也在 Windows 7 上开发服务器。深入研究文档后,我能够通过注册自己的错误处理程序来处理异常,该处理程序忽略客户端断开连接时抛出的错误处理程序。
  • 酷。你能分享你的代码吗?我认为这对正在处理类似问题的其他人是有益的。
  • 绝对!回家后我会用我的代码发布答案。

标签: javascript c++ html poco server-sent-events


【解决方案1】:

对于任何感兴趣的人,我可以通过注册自己的错误处理程序来处理这个问题,该处理程序只是忽略 SSE 客户端断开连接时引发的异常:

#include <Poco\ErrorHandler.h>

// Other includes, using namespace..., etc.

class ServerErrorHandler : public ErrorHandler
{
public:
    void exception(const Exception& e)
    {
        // Ignore an exception that's thrown when an SSE connection is closed. 
        //
        // Info: When the server is handling an SSE request, it keeps a persistent connection through a forever loop.
        //       In order to handle when a client disconnects, the request handler must detect such an event. Alas, this
        //       is not possible with the current request handler in Poco (we only have 2 params: request and response).
        //       The only hack for now is to simply ignore the exception generated when the client disconnects :(
        //
        if (string(e.className()).find("ConnectionAbortedException") == string::npos)
            poco_debugger_msg(e.what());
    }
};

class ServerApp : public ServerApplication 
{
protected:
    int main(const vector<string>& args) 
    {
        // Create and register our error handler
        ServerErrorHandler error_handler;
        ErrorHandler::set(&error_handler);

        // Normal server code, for example:
        HTTPServer server(new RequestHandlerFactory, 80, new HTTPServerParams);
        server.start();

        waitForTerminationRequest();
        server.stop();

        return Application::EXIT_OK;
    }
};


POCO_SERVER_MAIN(ServerApp);

但是,我必须说这是一个丑陋的 hack。此外,错误处理程序对应用程序来说是全局的,这使得它作为解决方案更不受欢迎。正确的方法是检测断开连接并进行处理。为此,Poco 必须将 SocketStream 传递给请求处理程序。

【讨论】:

    【解决方案2】:

    您可以更改代码以捕获 Poco 异常:

    try {
        MyServerApp myServer;
        return myServer.run(argc, argv);        
    }catch(const Poco::Exception& ex) {
        std::cout << ex.displayText() << std::endl;
        return Poco::Util::Application::EXIT_SOFTWARE;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-29
      • 1970-01-01
      • 1970-01-01
      • 2020-06-20
      • 1970-01-01
      • 1970-01-01
      • 2013-05-01
      • 2015-09-24
      相关资源
      最近更新 更多