Skip to content

WebSocket sendFrame Delay and ReceiveTimeout Dependency - Need Help #4756

@The-Robin-Hood

Description

@The-Robin-Hood

Hi,
I'm having a problem with Poco::Net::WebSocket.sendFrame(). It takes forever (about 2 seconds) to execute in a non-blocking context. It seems that sendFrame() only works when a receive timeout happens, which makes the receiving end laggy and timeouty. I tried setting the WebSocket to non-blocking mode with ws->setBlocking(false), but that didn't help. If I set ws->setReceiveTimeout(Poco::Timespan(0, 1000)), the receive timeout keeps getting called, and sendFrame() doesn't lag at all.

What am I missing? Should I set the timeout low, catch it, and then ignore it? I'd appreciate any help or suggestions.
I've attached a sample code below.

#include <chrono>
#include <iostream>
#include <thread>

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

class WebSocketClient {
   private:
    Poco::Net::WebSocket* ws;
    std::thread receiveThread;
    std::atomic<bool> running{true};

   public:
    WebSocketClient(const std::string& host, uint16_t port, const std::string& path) {
        Poco::Net::Context::Ptr context = new Poco::Net::Context(
            Poco::Net::Context::CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_NONE, 9, false,
            "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");

        Poco::Net::HTTPSClientSession session(host, port, context);
        session.setTimeout(Poco::Timespan(5, 0)); 
        Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, path,
                                       Poco::Net::HTTPMessage::HTTP_1_1);
        Poco::Net::HTTPResponse response;

        ws = new Poco::Net::WebSocket(session, request, response);
        // ws->setReceiveTimeout(Poco::Timespan(0, 1000)); 
        receiveThread = std::thread(&WebSocketClient::receiveLoop, this);
    }

    ~WebSocketClient() {
        running = false;
        if (receiveThread.joinable()) {
            receiveThread.join();
        }
        delete ws;
    }

    bool sendMessage(const std::string& message) {
        try {
            auto start = std::chrono::steady_clock::now();

            int flags = Poco::Net::WebSocket::FRAME_TEXT;
            int sent = ws->sendFrame(message.data(), message.length(), flags);

            auto end = std::chrono::steady_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);

            std::cout << "Time taken for sendFrame: " << duration.count() << " ms\n";

            return sent == message.length();
        } catch (const Poco::TimeoutException& e) {
            std::cerr << "Timeout sending message: " << e.what() << std::endl;
            return false;
        } catch (const Poco::Exception& e) {
            std::cerr << "Error sending message: " << e.what() << std::endl;
            return false;
        }
    }

   private:
    void receiveLoop() {
        const int BUFFER_SIZE = 1024;
        char buffer[BUFFER_SIZE];
        int flags = 0;

        while (running) {
            try {
                int received = ws->receiveFrame(buffer, sizeof(buffer), flags);
                if (received > 0) {
                    std::string message(buffer, received);
                    std::cout << "Received message: " << message << std::endl;
                }
            } catch (const Poco::TimeoutException&) {
                std::cerr << "Timeout receiving message\n";
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
                continue;
            } catch (const Poco::Exception& e) {
                std::cerr << "Error in receive loop: " << e.what() << std::endl;
                break;
            }
        }
    }
};

int main() {
    try {
        WebSocketClient client("echo.websocket.org", 443, "/");

        while (true) {
            std::cout << "Sending message: test\n";
            client.sendMessage("test");
            std::this_thread::sleep_for(std::chrono::seconds(3));
        }
    } catch (const Poco::Exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}```

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions