Connect Websocket with Poco libraries

8.4k Views Asked by At

I am trying to connect to the Echo Test Websocket using the Poco C++ libraries. In order to do so here is my code which should set up the Websocket:

HTTPClientSession cs("echo.websocket.org");
HTTPRequest request(HTTPRequest::HTTP_GET, "/ws");
HTTPResponse response;

WebSocket* m_psock = new WebSocket(cs, request, response);
m_psock->close(); //close immidiately

However it does not work: I am getting an error message like this:

Poco::Exception: WebSocket Exception: Cannot upgrade to WebSocket connection: Not Found

Can anybody help?

4

There are 4 best solutions below

0
Kevin H. Patterson On BEST ANSWER

The 'Not Found' error is the standard HTTP 404 Not Found returned by the HTTP server. It generally means the resource you are requesting does not exist.

I got your code to work by changing the resource from "/ws" to "/":

HTTPRequest request(HTTPRequest::HTTP_GET, "/");

and adding the following line

request.set("origin", "http://www.websocket.org");

before creating the new WebSocket. I think it's a header pair that many (or all?) WebSocket servers expect.

0
Olof On

If you want to get a reply from the echo server you must also make sure to use a Http 1.1 request. Poco defaults to Http 1.0.

HTTPRequest request(HTTPRequest::HTTP_GET, "/",HTTPMessage::HTTP_1_1);

This is a complete example,

#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>

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


int main(int args,char **argv)
{
    HTTPClientSession cs("echo.websocket.org",80);    
    HTTPRequest request(HTTPRequest::HTTP_GET, "/?encoding=text",HTTPMessage::HTTP_1_1);
    request.set("origin", "http://www.websocket.org");
    HTTPResponse response;


    try {

        WebSocket* m_psock = new WebSocket(cs, request, response);
        char *testStr="Hello echo websocket!";
        char receiveBuff[256];

        int len=m_psock->sendFrame(testStr,strlen(testStr),WebSocket::FRAME_TEXT);
        std::cout << "Sent bytes " << len << std::endl;
        int flags=0;

        int rlen=m_psock->receiveFrame(receiveBuff,256,flags);
        std::cout << "Received bytes " << rlen << std::endl;
        std::cout << receiveBuff << std::endl;

        m_psock->close();

    } catch (std::exception &e) {
        std::cout << "Exception " << e.what();
    }

}
0
Jason On

This is complete example for a 'wss' (i.e. secure) connection.

#include "Poco/Exception.h"
#include "Poco/Net/AcceptCertificateHandler.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/Websocket.h"
#include "Poco/SharedPtr.h"
#include "Poco/URI.h"

int main(int args, char **argv) {
  Poco::URI uri("wss://ws.postman-echo.com/raw");

  Poco::Net::initializeSSL();

  Poco::Net::Context::Params params;
  params.verificationMode = Poco::Net::Context::VERIFY_NONE;
  params.verificationDepth = 9;
  params.loadDefaultCAs = true;
  params.cipherList = "ALL";

  Poco::Net::Context::Ptr context = new Poco::Net::Context(Poco::Net::Context::TLSV1_2_CLIENT_USE, params);

  // This accepts all certificates. Even invalid ones.
  // Use for testing only.
  Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> ptrCert = new Poco::Net::AcceptCertificateHandler(false);

  Poco::Net::SSLManager::instance().initializeClient(NULL, ptrCert, context);

  auto port = uri.getPort();
  auto host = uri.getHost();
  Poco::Net::HTTPClientSession httpSession(host, port);

  auto path = uri.getPath();
  Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, path, Poco::Net::HTTPMessage::HTTP_1_1);
  request.set("origin", "http://ws.postman-echo.com/raw");
  Poco::Net::HTTPResponse response;

  try {
    Poco::Net::WebSocket m_psock(httpSession, request, response);
    std::string testStr = "Hello echo websocket!";
    char receiveBuff[256];

    int len = m_psock.sendFrame(testStr.c_str(), testStr.length(), Poco::Net::WebSocket::FRAME_TEXT);
    std::cout << "Sent message " << testStr << std::endl;
    std::cout << "Sent bytes " << len << std::endl;
    int flags = 0;

    int rlen = m_psock.receiveFrame(receiveBuff, 256, flags);
    std::cout << "Recv bytes " << rlen << std::endl;
    std::string received(receiveBuff, rlen);
    std::cout << "Recv message " << received << std::endl;

    m_psock.close();

  } catch (std::exception &e) {
    std::cout << "Exception " << e.what();
  }
}
0
Markus On

I combined the code of Olof and Jason. Setting the origin of the request is (no longer?) necessary.

Compiles with

g++ -std=c++20 -o websocket-poco websocket-poco.cpp  -lPocoRedis -lPocoUtil -lPocoNet -lPocoNetSSL -lPocoCrypto -lPocoXML -lPocoJSON -lPocoFoundation

Requires

sudo apt install libpoco-dev

Result

Hello initially!        (Request served by 7811941c69e658)
Hello again!
And again!

Save to websocket-poco.cpp

#include <iostream>
#include <Poco/Net/AcceptCertificateHandler.h>
#include <Poco/Net/HTTPMessage.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/Net/HTTPSClientSession.h>
#include <Poco/Net/WebSocket.h>

using Poco::Net::HTTPMessage;
using Poco::Net::HTTPRequest;
using Poco::Net::HTTPResponse;
using Poco::Net::HTTPSClientSession;
using Poco::Net::WebSocket;
using std::cout;
using std::string;


WebSocket open(string host, string path){
    HTTPSClientSession  session (host);
    HTTPRequest         request (HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
    HTTPResponse        response;
    return WebSocket (session, request, response);
}


string receiveFrame (WebSocket websocket) {
    int   FRAME_OP_CONT = WebSocket::FRAME_OP_CONT;
    int   max_size = 1024;
    char  frame_buffer[max_size];
    int   actual_size = websocket.receiveFrame(frame_buffer, max_size, FRAME_OP_CONT);
    return string (frame_buffer, actual_size);
}


string echo (WebSocket websocket, string text, bool initial_request = false) {
    string initial_response, response;
    websocket.sendFrame (text.c_str(), text.length(), WebSocket::FRAME_TEXT);
    if (initial_request) {
      initial_response  = receiveFrame(websocket);
    }
    response            = receiveFrame(websocket);
    if (initial_request) {
      response += "        (" + initial_response + ")";
    }
    return response;
}


int main() {
    auto websocket  = open("echo.websocket.org", "/");
    auto response_1 = echo(websocket, "Hello initially!", true);
    auto response_2 = echo(websocket, "Hello again!");
    auto response_3 = echo(websocket, "And again!");
    websocket.close();

    cout <<  response_1 << "\n";
    cout <<  response_2 << "\n";
    cout <<  response_3 << "\n";
}