Как я могу запустить несколько ServerApplications с POCO C++?

Я начал изучать библиотеку POCO C++ и застрял при попытке запустить 2 сервера в одном приложении (чтобы они могли использовать некоторые общие переменные времени выполнения). Это 2 разных сервера, один из которых - TCP TimeServer, а другой - простой UDP EchoServer. Код:

#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Net/TCPServerParams.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Timestamp.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/Exception.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include <iostream>


using Poco::Net::ServerSocket;
using Poco::Net::StreamSocket;
using Poco::Net::TCPServerConnection;
using Poco::Net::TCPServerConnectionFactory;
using Poco::Net::TCPServer;
using Poco::Timestamp;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::Util::ServerApplication;
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;


class TimeServerConnection : public TCPServerConnection
{
public:
    TimeServerConnection(const StreamSocket& s, const std::string& format) :
        TCPServerConnection(s),
        _format(format)
    {
    }

    void run()
    {
        Application& app = Application::instance();

        bool isOpen = true;
        Poco::Timespan timeOut(10, 0);
        unsigned char incommingBuffer[1000];

        app.logger().information("SYSLOG from " + this->socket().peerAddress().toString());

        while (isOpen) {
            if (socket().poll(timeOut, Poco::Net::Socket::SELECT_READ) == false) {
                std::cout << "TIMEOUT!" << std::endl << std::flush;
            } else {
                int nBytes = -1;
                try {
                    nBytes = socket().receiveBytes(incommingBuffer, sizeof(incommingBuffer));
                    std::cout << incommingBuffer << std::endl;
                } catch (Poco::Exception& exc) {
                    std::cerr << "Network error: " << exc.displayText() << std::endl;
                    isOpen = false;
                }

                if (nBytes == 0) {
                    std::cout << "Client closes connection!" << std::endl << std::flush;
                    isOpen = false;
                } else {
                    std::cout << "Receiving nBytes: " << nBytes << std::endl << std::flush;
                }
            }
        }

        try
        {
            Timestamp now;
            std::string dt(DateTimeFormatter::format(now, _format));
            dt.append("\r\n");
            socket().sendBytes(dt.data(), (int)dt.length());
        }
        catch (Poco::Exception& exc)
        { app.logger().log(exc); }
    }

private:
    std::string _format;
};


class TimeServerConnectionFactory : public TCPServerConnectionFactory
{
public:
    TimeServerConnectionFactory(const std::string& format) :
        _format(format)
    {
    }

    TCPServerConnection* createConnection(const StreamSocket& socket)
    { return new TimeServerConnection(socket, _format); }

private:
    std::string _format;
};


class UDPServer : public Poco::Util::ServerApplication
{
public:
    UDPServer(){}
    ~UDPServer(){}

protected:
    void initialize(Application& self)
    {
        loadConfiguration(); // load default configuration files, if present
        ServerApplication::initialize(self);
    }

    void uninitialize() { ServerApplication::uninitialize(); }

    int main(const std::vector<std::string>& args)
    {

        unsigned short port = (unsigned short)config().getInt("udpport", 9002);
        std::cout << "[UDP] Using port " << port << std::endl;
        std::string format(config().getString("TimeServer.format", DateTimeFormat::ISO8601_FORMAT));

        Poco::Net::SocketAddress socketaddress(Poco::Net::IPAddress(), 9001);
        Poco::Net::DatagramSocket datagramsocket(socketaddress);
        char buffer[1024]; // 1K byte

        while (1) {
            Poco::Net::SocketAddress sender;
            int n = datagramsocket.receiveFrom(buffer, sizeof(buffer) - 1, sender);
            buffer[n] = '\0';
            std::cout << sender.toString() << ":" << buffer << std::endl;
        }
        return 0;
    }
};

class TimeServer : public Poco::Util::ServerApplication
{
public:
    TimeServer() : _helpRequested(false)
    {
    }

    ~TimeServer()
    {
    }

protected:
    void initialize(Application& self)
    {
        loadConfiguration(); // load default configuration files, if present
        ServerApplication::initialize(self);
    }

    void uninitialize()
    {
        ServerApplication::uninitialize();
    }

    void defineOptions(OptionSet& options)
    {
        ServerApplication::defineOptions(options);

        options.addOption(
            Option("help", "h", "display help information on command line arguments")
            .required(false)
            .repeatable(false));
    }

    void handleOption(const std::string& name, const std::string& value)
    {
        ServerApplication::handleOption(name, value);

        if (name == "help")
            _helpRequested = true;
    }

    void displayHelp()
    {
        HelpFormatter helpFormatter(options());
        helpFormatter.setCommand(commandName());
        helpFormatter.setUsage("OPTIONS");
        helpFormatter.setHeader("A server application that serves the current date and time.");
        helpFormatter.format(std::cout);
    }

    int main(const std::vector<std::string>& args)
    {
        if (_helpRequested)
        {
            displayHelp();
        }
        else
        {
            unsigned short port = (unsigned short)config().getInt("tcpport", 9911);
            std::cout << "Using port " << port << std::endl;
            std::string format(config().getString("TimeServer.format", DateTimeFormat::ISO8601_FORMAT));

            ServerSocket svs(port);
            TCPServer srv(new TimeServerConnectionFactory(format), svs);
            srv.start();
            std::cout << "Server started!\n";
            waitForTerminationRequest();
            srv.stop();
            std::cout << "Server stopped!\n";
        }
        return Application::EXIT_OK;
    }

private:
    bool _helpRequested;
};


int main(int argc, char** argv)
{
    TimeServer app;
    UDPServer app2;
    app.run(argc, argv);
    app2.run(argc, argv);
}

В конце кода у меня есть int main() метод, в котором я пытаюсь запустить 2 сервера. Однако я получаю нарушение утверждения здесь. Есть похожий вопрос по Stackru, однако boost используется там, в то время как я использую простой C++, так что решение не относится ко мне.

Как я могу запустить одновременно эти 2 сервера?

2 ответа

ServerApplication не был предназначен для нескольких экземпляров. Что вы должны сделать, это запустить один ServerApplication и запустите TCPServer и UDPServer в этом приложении.

На самом деле, если вы хотите сделать так (как вы задаете вопрос), разделите класс tcp (a) и класс udp (b).

Вызовите оба из другого класса (c) и определите, какой (c) -> (a) (c) -> (b) вам нужно вызвать первым и когда. Так что вам нужно принять условие и решение.

Примечание: дайте им время перед бегом, чтобы сделать дыхание поко.

Другие вопросы по тегам