C++,Poco Socketstream到WebSocket,用于JSON数据包传输

cedebl8k  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(255)

我正在做一个非常依赖数据包延迟的项目。整个系统的架构师希望使用Poco::Net::WebSocket协议作为不同节点之间的传输层。到目前为止,我们一直在使用ZMQ运行应用程序,但是开销太大,我们没有看到我们需要的速度。所以我的任务是将系统的ZMQ部分转换为WebSocket。
我从来没有使用过WebSocket,我有问题,理解是怎么回事.我知道WebSocket最初是作为一种方式来加快网页浏览器和页面服务器之间的通信减少延迟通过使用全双工双向通信.
有很多关于JavaScript、nodejs甚至python的教程,但当你谈论C++时,它就更有限了,这就是我正在使用的。我发现的例子更多地面向浏览器请求,我并不感到惊讶。而不是一般的TCP数据包传输,这是我们的用例。
以下是我的想法和问题。
看到我无法真正理解发生了什么,我决定先从Poco::Net::SocketStream配置开始。我选择这样做是基于Websockets只不过是插入到更高级别协议框架中的TCP套接字的想法。我认为转换比从头开始更容易。所以我使用标准Poco套接字库启动了一个服务器和客户端应用程序。
我以here为基础,最后把所有东西都移到了一个文件中。我还创建了一个Poco::Net::TCP服务器,一个here的示例。
我修改了这两个,以管理我在客户端和服务器之间发送JSON数据包的事实。我采取了我们原始代码的片段来格式化JSON数据包,并使用CBOR对其进行编码。我最终保留了我最初使用的zmq::message_t格式,因为我在另一端接收数据包时遇到了问题。因此,由于这不是主要问题,我现在跳过了这一部分。所以我知道下面代码的ZMQ部分是不必要的,这是一个小问题。
下面是客户端代码供参考。

#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/HTTPMessage.h"
#include "Poco/Net/WebSocket.h"
#include "Poco/Net/HTTPClientSession.h"
#include <iostream>

#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/SocketStream.h"
#include "Poco/Net/WebSocket.h"
#include <jsoncons/json.hpp>
#include <jsoncons/json.hpp>
#include <jsoncons_ext/cbor/cbor.hpp>
#include <jsoncons_ext/jsonpath/json_query.hpp>
#include <jsoncons_ext/jsonpath/jsonpath.hpp>

#include <iostream>
#include <string>
#include <zmq.hpp>

using namespace jsoncons;
using Poco::Net::HTTPClientSession;
using Poco::Net::HTTPMessage;
using Poco::Net::HTTPRequest;
using Poco::Net::HTTPResponse;
using Poco::Net::WebSocket;

class ClientHandler
{
private:
    std::string host;
    int port;

    // IP endpoint/socket address (consists of host addr and port #)
    Poco::Net::SocketAddress socketAddr;

    // Interface to a TCP stream socket
    // Poco::Net::StreamSocket socket;
    Poco::Net::Socket socket;

    // Stream for reading from / writing to a socket (accepts a socket)
    Poco::Net::SocketStream stream;

public:
    ClientHandler(std::string h, int p) : host(h), port(p), socketAddr(h, p), socket(), stream(socket)
    {
        std::cout << "Host: " << host << "\tPort: " << port << std::endl;
    }

    // Connect to the initialized socket address' hostname and port
    bool connected()
    {
        std::cout << "Creating a connection with ["
                  << socketAddr.host().toString()
                  << "] through port [" << socketAddr.port() << "] ...";
        try
        {
            // socket.connect(socketAddr);
            // std::cout << "Success!" << std::endl;
        }
        catch (Poco::Exception err)
        {
            std::cout << std::endl;
            std::cout << "Socket connection error: [" << err.displayText() << "]" << std::endl;
            return false;
        }
        return true;
    }

    // Send a message to the connected server
    bool sendMessage()
    {
        std::cout << std::endl;
        const char channel[] = "fool";
        std::string channelPort = std::to_string(5577);

        try
        {
            std::string message;

            std::cout << "Enter a message to send to the server: ";
            std::cin >> message;

            json msg = json(json_object_arg, {{"$op", "create_channel"}, {"$svc", "zmq"}, {"channel_name", channel}, {"port", channelPort}});
            std::vector<uint8_t> buffer;
            jsoncons::cbor::encode_cbor(msg, buffer);
            zmq::const_buffer msg_out = zmq::buffer(buffer);

            if (message.compare("exit") != 0)
            {
                std::cout << "Sending the message to the server!\n\t";
                // socket.sendBytes(msg_out.data(), msg_out.size());
                return true;
            }
            else
                return false;
        }
        catch (Poco::Exception err)
        {
            std::cout << "Data send error: [" << err.displayText() << "]" << std::endl;
            return false;
        }
    }
};

int main(int argc, char **argv)
{
    int port = 2001;
    std::string hostname = "10.0.12.97";

    // Handle the server-client connection and send some JSON
    try
    {
        ClientHandler handler(hostname, port);

        if (handler.connected())
            while (handler.sendMessage())
                ;
    }
    catch (Poco::Exception err)
    {

        std::cout << "Handler Error -> " << err.displayText() << std::endl;
    }

    return 0;
}

字符串
那么,我如何从这个^到Websockets?
我一直在阅读和挖掘Poco Websockets的文档。起初,我认为我需要弄清楚我在很多例子中看到的HTTPClientSession,HTTPRequest和HTTPResponse对象。然而,查看Poco Websockets构造函数的文档,似乎我所需要做的就是传递一个套接字连接。所以花了一些时间试图弄清楚,但是在回到文档之后,它似乎指定我需要向它发送一个已经是WebSocket的套接字。

Creates a WebSocket from another Socket, which must be a WebSocket,


这就是我没有真正阅读它的结果,所以我花了更多的时间阅读构造函数,看起来我实际上至少要发送3个参数。

WebSocket
WebSocket(
    HTTPClientSession & cs,
    HTTPRequest & request,
    HTTPResponse & response
);

Creates a client-side WebSocket, using the given HTTPClientSession and HTTPRequest for the initial handshake (HTTP Upgrade request).


所以我现在回到HTTPClientSession、HTTPRequest和HTTPResponse对象。
我想我理解HTTPClientSession。这里我应该提供服务器名称和端口。因此,更新上面的代码应该如下所示:

...
Poco::Net::HTTPClientSession cs;

public:
    ClientHandler(std::string h, int p) : host(h), port(p), cs(h, p) 
...


HTTPResponse看起来是一个指向响应对象的指针,用于WebSocket返回HTTPRequest响应。看起来包含状态代码,日期,原因(不确定原因是什么)
HTTPRequest是一个有趣的地方。我不知道我需要把它格式化为什么。这个请求有三个参数。

  • 方法--这看起来只不过是告诉服务器你正在请求一些东西或者希望移交一些东西。
  • HTTP_POST -我假设这是我想要的?
  • HTTP_GET
  • URI -对于HTTP_GET,这将是我要检索的资源的路径。对于Post,这将是我想在服务器上发布内容的路径
  • 版本-看起来是不言自明的,因为这是我想使用的HTTP版本。

但这里是它的摩擦,我不想发布/获取任何与URI相关联的东西,我只是想传输一个JSON数据包,并在另一端管理它。我发现一个sample code of a client使用此信息,但我不明白为什么它使用HTTP_GET,和/?encode=text reference。我似乎找不到它的任何细节。这让我想到了请求对象的set值,不明白“set()”调用是为了什么,也不明白它在我的情况下是如何工作的。
有了新的信息,我更新了我的构造函数。

...
Poco::Net::WebSocket *ws;

public:
    ClientHandler(std::string h, int p) : host(h), port(p)
    {
        std::cout << "TEST" << std::endl;
        
        // Poco::Net::HTTPClientSession cs(h, p);         
        Poco::Net::HTTPClientSession cs(host, port);
        Poco::Net::HTTPRequest req(HTTPRequest::HTTP_GET, "/?encoding=text", HTTPMessage::HTTP_1_1);
        // req.set("origin", "http://www.websocket.org");
        Poco::Net::HTTPResponse resp;

        ws = new WebSocket(cs, req, resp);

        std::cout << "Host: " << host << "\tPort: " << port << std::endl;
    }
...


然而,我进入了构造函数,但从未离开它。当我试图创建WebSocket时,它会挂起。我假设它不喜欢某些东西。我尝试了HTTPClientSesseion cs两种方法。并保留req.set()。只是挂起。
有人能告诉我如何运行Poco::Net::WebSocket吗?还有一些信息,这样我就能更好地理解发生了什么。所以当我尝试服务器端时,我会有更多的信息来帮助我。

ncgqoxb0

ncgqoxb01#

我今天开始使用Poco,需要实现一个发送和接收JSON消息的WebSocket客户端。下面是一个“最低限度”的类,它 Package 了Poco所需的功能:

#include <iostream>
#include <Poco/Buffer.h>
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/Net/WebSocket.h>

using namespace Poco::Net;

class PocoWebSocket
{
public:
    PocoWebSocket(std::string const & host, Poco::UInt16 port, std::string const & route)
        : _session(host, port)
        , _request(HTTPRequest::HTTP_GET, route + "?encoding=text",
                   HTTPRequest::HTTP_1_1)
        , _socket(_session, _request, _response)
    {}
    ~PocoWebSocket() { _socket.shutdown(); }

public:
    void sendTextFrame  (std::string_view msg) { sendImpl(msg, WebSocket::FRAME_TEXT);   }
    void sendBinaryFrame(std::string_view msg) { sendImpl(msg, WebSocket::FRAME_BINARY); }
    auto receiveTextFrame() -> std::string
    {
        int flags = 0;
        Poco::Buffer<char> buffer(0);
        auto const sz = _socket.receiveFrame(buffer, flags);
        return std::string(buffer.begin(), static_cast<std::size_t>(sz));
    }

private:
    void sendImpl(std::string_view msg, WebSocket::SendFlags flags)
    {
        _socket.sendFrame(msg.data(), msg.size(), flags);
    }

private:
    HTTPClientSession _session;
    HTTPRequest       _request;
    HTTPResponse      _response;
    WebSocket         _socket;
};

static int die(int exitCode, std::string const & msg)
{
    std::cerr << "[FATAL] " << msg << std::endl;
    return exitCode;
}

int main() try
{
    PocoWebSocket socket("localhost", HTTPSession::HTTP_PORT, "/");
    auto const msg = socket.receiveTextFrame();
    std::cout << "recv: " << msg << std::endl;
    // parse JSON here
}
catch (Poco::Exception const & e) { return die(e.code(), e.displayText()); }
catch (std::exception  const & e) { return die(EXIT_FAILURE, e.what());    }

字符串

相关问题