POCO — могу ли я использовать SocketReactor в качестве клиента?

Я вижу много примеров использования SocketReactor в сочетании с SocketAcceptor, когда люди используют TCP-сервер.

Однако я хочу подключиться к существующему TCP-серверу в качестве клиента, но хотел бы иметь возможность обрабатывать события, предоставляемые SocketReactor, такие как onSocketReadable, onSocketWritable, onSocketShutdown, onSocketError и onSocketTimeout.

Это возможно с библиотеками POCO? Я собрал следующий код, но ни одно из событий не сработало.
Если этот подход не работает, какие-либо другие предложения?
По сути, я буду получать поток tcp-сообщений в режиме реального времени с сервера, а также отправлять сообщения обратно на сервер для выполнения определенных задач.

class ITCHProvider
{
private:
Poco::Net::SocketAddress _sa;
Poco::Net::StreamSocket _sock;
Poco::Net::SocketStream _stream;
Poco::Net::SocketReactor _reactor;

public:
ITCHProvider() :
_sa("host", 1234),
_sock(),
_stream(_sock),
_reactor()
{
_reactor.addEventHandler(_sock, Poco::NObserver<ITCHProvider, Poco::Net::ReadableNotification>(*this, &ITCHProvider::onSocketReadable));
_reactor.addEventHandler(_sock, Poco::NObserver<ITCHProvider, Poco::Net::WritableNotification>(*this, &ITCHProvider::onSocketWritable));
_reactor.addEventHandler(_sock, Poco::NObserver<ITCHProvider, Poco::Net::ShutdownNotification>(*this, &ITCHProvider::onSocketShutdown));
_reactor.addEventHandler(_sock, Poco::NObserver<ITCHProvider, Poco::Net::ErrorNotification>(*this, &ITCHProvider::onSocketError));
_reactor.addEventHandler(_sock, Poco::NObserver<ITCHProvider, Poco::Net::TimeoutNotification>(*this, &ITCHProvider::onSocketTimeout));

_sock.connect(_sa);
}

~ITCHProvider()
{
close();
}

void onSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf)
{
LOG(INFO) << "READable   !!";
}
void onSocketWritable(const Poco::AutoPtr<Poco::Net::WritableNotification>& pNf)
{
LOG(INFO) << "WRITEable   !!";
}
void onSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf)
{
LOG(INFO) << "SHUTDOWN!!!!!!!!!!!!";
}
void onSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf)
{
LOG(INFO) << "Error!!";
}
void onSocketTimeout(const Poco::AutoPtr<Poco::Net::TimeoutNotification>& pNf)
{
LOG(INFO) << "Timeout!!";
}

// Close down the connection properly.
void close() {
try {
_sock.shutdown();
}
catch (...) {
LOG(INFO) << "closing failed.";
}
}

};

0

Решение

Может быть сделано, но учтите, что (а) ничего не произойдет, пока вы фактически не запустите реактор, и (б) реактор не будет вращаться, пока явно не остановится, поэтому лучше всего запускать его в отдельном потоке;

вот быстрый пример:

// server-side handler
class EchoServiceHandler {
public:
EchoServiceHandler(StreamSocket& socket, SocketReactor& reactor): _socket(socket), _reactor(reactor) {
_reactor.addEventHandler(_socket, Observer<EchoServiceHandler, ReadableNotification>(*this, &EchoServiceHandler::onReadable));
}

~EchoServiceHandler() {
_reactor.removeEventHandler(_socket, Observer<EchoServiceHandler, ReadableNotification>(*this, &EchoServiceHandler::onReadable));
}

void onReadable(ReadableNotification* pNf) {
pNf->release();
char buffer[8];
int n = _socket.receiveBytes(buffer, sizeof(buffer));
if (n > 0) {
_socket.sendBytes(buffer, n);
}
else {
_socket.shutdownSend();
delete this;
}
}

private:
StreamSocket   _socket;
SocketReactor& _reactor;
};

Ваш оригинальный код, слегка измененный:

class ITCHProvider : public Poco::Runnable
{
private:
Poco::Net::StreamSocket _sock;
Poco::Net::SocketReactor _reactor;

public:
ITCHProvider(const SocketAddress& sa) : _sock(sa) {
_reactor.addEventHandler(_sock, Poco::NObserver<ITCHProvider, Poco::Net::ReadableNotification>(*this, &ITCHProvider::onSocketReadable));
_reactor.addEventHandler(_sock, Poco::NObserver<ITCHProvider, Poco::Net::WritableNotification>(*this, &ITCHProvider::onSocketWritable));
_reactor.addEventHandler(_sock, Poco::NObserver<ITCHProvider, Poco::Net::ShutdownNotification>(*this, &ITCHProvider::onSocketShutdown));
_reactor.addEventHandler(_sock, Poco::NObserver<ITCHProvider, Poco::Net::ErrorNotification>(*this, &ITCHProvider::onSocketError));
_reactor.addEventHandler(_sock, Poco::NObserver<ITCHProvider, Poco::Net::TimeoutNotification>(*this, &ITCHProvider::onSocketTimeout));
std::string data = "Hello reactor world!";
_sock.sendBytes(data.data(), (int)data.length());
}

~ITCHProvider() { close(); }

void run() { _reactor.run(); }
void stop() { _reactor.stop(); }

void onSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
std::cout << "READable   !!" << std::endl;
char data[1025] = { 0 };
if (_sock.receiveBytes(data, 1024) > 0) {
std::cout << data << std::endl;
}
}
void onSocketWritable(const Poco::AutoPtr<Poco::Net::WritableNotification>& pNf) {
std::cout << "WRITEable   !!" << std::endl;
}
void onSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
std::cout << "SHUTDOWN!!!!!!!!!!!!" << std::endl;
}
void onSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf) {
std::cout << "Error!!" << std::endl;
}
void onSocketTimeout(const Poco::AutoPtr<Poco::Net::TimeoutNotification>& pNf) {
std::cout << "Timeout!!" << std::endl;
}

void close() {
try {
_sock.shutdown();
}
catch (...) {
std::cout << "closing failed." << std::endl;
}
}
};

Теперь давайте запустим выше:

SocketAddress ssa;
ServerSocket ss(ssa);
SocketReactor reactor;
SocketAcceptor<EchoServiceHandler> acceptor(ss, reactor);
Thread server;
server.start(reactor);
ITCHProvider provider(SocketAddress("127.0.0.1", ss.address().port()));
Thread client;
client.start(provider);
Thread::sleep(1000);
reactor.stop();
provider.stop();
server.join();
client.join();

Вывод (доступный для записи и тайм-аут уведомления для ясности):

READable   !!
Hello reactor world!
SHUTDOWN!!!!!!!!!!!!
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]