Input Available Logs in wxWidgets socket example with for-loop in Client.cpp OnTest2 function - c++

I am beginning to learn about sockets in wxWidgets, and run on Windows 10 (latest version), CodeBlocks 20.03 with mingw2 (gnu 11.2), and wxWidgets 3.15.
The socket sample compiles and run OK.
Because I will be sending many wxStrings (up to 7000 in one session) from the client to the server, I added a for-loop in the client.cpp OnTest2 function (see below).
Where the single transfer of the original socket sample runs OK every time, the adapted client.cpp OnTest2 function always logs Input-Available events at various locations.
For some reason "Input-Available" is logged on all sends.
The Server receives everything, so I am not worried that much about the future content.
Still, these Input-Available Log messages should not happen, I think.
I read somewhere that calling wxThread::Yield() prior to calling WaitForRead() would help, but it did not.
Is something wrong in my "simple" approach of adding a for-loop?
I hope someone can help me understand why these Input-Available log message appear,
and help me find a solution.
Edit:
I have reduced the wxWidgets socket examples to the smallest of my 'beginners' abilities.
minclient.cpp
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
# include "wx/wx.h"
#endif
#include "wx/socket.h"
#include "wx/sstream.h"
class MyApp : public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE;
};
class MyFrame : public wxFrame
{
public:
MyFrame();
~MyFrame();
void OnQuit(wxCommandEvent& event);
void OnOpenConnection(wxCommandEvent& event);
void OnCloseConnection(wxCommandEvent& event);
void OpenConnection(wxSockAddress::Family family);
void OnSocketEvent(wxSocketEvent& event);
void OnTest(wxCommandEvent& event);
private:
wxSocketClient *m_sock;
wxMenu *m_menuFile;
wxMenu *m_menuSocket;
wxMenuBar *m_menuBar;
wxDECLARE_EVENT_TABLE();
};
enum
{
CLIENT_QUIT = wxID_EXIT,
CLIENT_ABOUT = wxID_ABOUT,
CLIENT_OPEN = 100,
CLIENT_TEST,
CLIENT_CLOSE,
SOCKET_ID
};
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(CLIENT_QUIT, MyFrame::OnQuit)
EVT_MENU(CLIENT_OPEN, MyFrame::OnOpenConnection)
EVT_MENU(CLIENT_TEST, MyFrame::OnTest)
EVT_MENU(CLIENT_CLOSE, MyFrame::OnCloseConnection)
EVT_SOCKET(SOCKET_ID, MyFrame::OnSocketEvent)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
if ( !wxApp::OnInit() )
return false;
MyFrame *frame = new MyFrame();
frame->Show(true);
return true;
}
MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, wxID_ANY,
_("wxSocket demo: Client"),
wxDefaultPosition, wxSize(300, 200))
{
m_menuFile = new wxMenu();
m_menuFile->AppendSeparator();
m_menuFile->Append(CLIENT_QUIT, _("E&xit\tAlt-X"), _("Quit client"));
m_menuSocket = new wxMenu();
m_menuSocket->Append(CLIENT_OPEN, _("&Open session\tCtrl-O"), _("Connect to server"));
m_menuSocket->AppendSeparator();
m_menuSocket->Append(CLIENT_TEST, _("Test &2\tCtrl-F2"), _("Test ReadMsg and WriteMsg"));
m_menuSocket->AppendSeparator();
m_menuSocket->Append(CLIENT_CLOSE, _("&Close session\tCtrl-C"), _("Close connection"));
m_menuBar = new wxMenuBar();
m_menuBar->Append(m_menuFile, _("&File"));
m_menuBar->Append(m_menuSocket, _("&TCP"));
SetMenuBar(m_menuBar);
m_sock = new wxSocketClient();
m_sock->SetEventHandler(*this, SOCKET_ID);
m_sock->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
m_sock->Notify(true);
}
MyFrame::~MyFrame()
{
delete m_sock;
}
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
Close(true);
}
void MyFrame::OnOpenConnection(wxCommandEvent& WXUNUSED(event))
{
OpenConnection(wxSockAddress::IPV4);
}
void MyFrame::OpenConnection(wxSockAddress::Family family)
{
wxIPaddress * addr;
wxIPV4address addr4;
addr = &addr4;
m_menuSocket->Enable(CLIENT_OPEN, false);
m_menuSocket->Enable(CLIENT_CLOSE, false);
wxString hostname = "localhost";
addr->Hostname(hostname);
addr->Service(3000);
m_sock->Connect(*addr, false);
}
void MyFrame::OnCloseConnection(wxCommandEvent& WXUNUSED(event))
{
m_sock->Close();
}
void MyFrame::OnSocketEvent(wxSocketEvent& event)
{
switch ( event.GetSocketEvent() )
{
case wxSOCKET_INPUT:
std::cout << "Input available on the socket.\n";
break;
case wxSOCKET_LOST:
std::cout << "Socket connection was unexpectedly lost.\n";
break;
case wxSOCKET_CONNECTION:
std::cout << "... socket is now connected.\n";
break;
default:
std::cout << "Unknown socket event!\n";
break;
}
}
void MyFrame::OnTest(wxCommandEvent& WXUNUSED(event))
{
for(int f = 0; f < 2; f++)
{
unsigned char c = 0xCE;
m_sock->Write(&c, 1);
m_sock->SetFlags(wxSOCKET_WAITALL);
wxString s = "This is my string to send";
const wxScopedCharBuffer msg1(s.utf8_str());
size_t len = wxStrlen(msg1) + 1;
wxCharBuffer msg2(wxStrlen(msg1));
m_sock->WriteMsg(msg1, len);
if(m_sock->Error())
{ std::cout << " Write failed !\n"; }
m_sock->WaitForRead(2);
if (m_sock->IsData())
{
m_sock->ReadMsg(msg2.data(), len);
if(m_sock->Error())
{ std::cout << " Read failed !\n"; }
else
{
if (memcmp(msg1, msg2, len) != 0)
{ std::cout << "Test failed !\n"; }
else
{ std::cout << "Returned msg: \"" << msg2 << "\"" << std::endl; }
}
}
else
{ std::cout << "Timeout ! Test failed.\n"; }
}
}
minserver.cpp
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
# include "wx/wx.h"
#endif
#include "wx/socket.h"
typedef wxIPV4address IPaddress;
class MyApp : public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE;
};
class MyFrame : public wxFrame
{
public:
MyFrame();
~MyFrame();
void OnQuit(wxCommandEvent& event);
void OnServerEvent(wxSocketEvent& event);
void OnSocketEvent(wxSocketEvent& event);
void Test(wxSocketBase *sock);
private:
wxSocketServer *m_server;
wxMenu *m_menuFile;
wxMenuBar *m_menuBar;
int m_numClients;
wxDECLARE_EVENT_TABLE();
};
enum
{
SERVER_QUIT = wxID_EXIT,
SERVER_ID = 100,
SOCKET_ID
};
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(SERVER_QUIT, MyFrame::OnQuit)
EVT_SOCKET(SERVER_ID, MyFrame::OnServerEvent)
EVT_SOCKET(SOCKET_ID, MyFrame::OnSocketEvent)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
if ( !wxApp::OnInit() )
return false;
MyFrame *frame = new MyFrame();
frame->Show(true);
return true;
}
MyFrame::MyFrame() : wxFrame((wxFrame *)NULL, wxID_ANY,
_("wxSocket demo: Server"),
wxDefaultPosition, wxSize(300, 200))
{
m_menuFile = new wxMenu();
m_menuFile->Append(SERVER_QUIT, _("E&xit\tAlt-X"), _("Quit server"));
m_menuBar = new wxMenuBar();
m_menuBar->Append(m_menuFile, _("&File"));
SetMenuBar(m_menuBar);
IPaddress addr;
addr.Service(3000);
m_server = new wxSocketServer(addr);
if (! m_server->IsOk())
{
std::cout << "Could not listen at the specified port !\n";
return;
}
IPaddress addrReal;
if ( !m_server->GetLocal(addrReal) )
{ std::cout << "ERROR: couldn't get the address we bound to.\n"; }
else
{ std::cout << "Server listening at " << addrReal.IPAddress() << ": " << addrReal.Service() << std::endl; }
m_server->SetEventHandler(*this, SERVER_ID);
m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
m_server->Notify(true);
m_numClients = 0;
}
MyFrame::~MyFrame()
{
delete m_server;
}
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
Close(true);
}
void MyFrame::OnServerEvent(wxSocketEvent& event)
{
wxString s = "OnServerEvent: ";
wxSocketBase *sock;
switch(event.GetSocketEvent())
{
case wxSOCKET_CONNECTION:
s.Append("wxSOCKET_CONNECTION");
break;
default:
s.Append("Unexpected event !");
break;
}
std::cout << s << std::endl;
sock = m_server->Accept(false);
if (sock)
{
IPaddress addr;
if ( !sock->GetPeer(addr) )
{ std::cout << "New connection from unknown client accepted.\n"; }
else
{ std::cout << "New client connection from " << addr.IPAddress() << ":" << addr.Service() << " accepted\n"; }
}
else
{
std::cout << "Error: couldn't accept a new connection\n";
return;
}
sock->SetEventHandler(*this, SOCKET_ID);
sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
sock->Notify(true);
m_numClients++;
}
void MyFrame::OnSocketEvent(wxSocketEvent& event)
{
wxString s = "OnSocketEvent: ";
wxSocketBase *sock = event.GetSocket();
switch(event.GetSocketEvent())
{
case wxSOCKET_INPUT:
s.Append(_("wxSOCKET_INPUT"));
break;
case wxSOCKET_LOST:
s.Append(_("wxSOCKET_LOST"));
break;
default:
s.Append(_("Unexpected event !"));
break;
}
std::cout << s << std::endl;
switch(event.GetSocketEvent())
{
case wxSOCKET_INPUT:
{
sock->SetNotify(wxSOCKET_LOST_FLAG);
unsigned char c;
sock->Read(&c, 1);
switch (c)
{
case 0xCE:
Test(sock);
break;
default:
std::cout << "Unknown test id received from client\n";
}
sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG);
break;
}
case wxSOCKET_LOST:
{
m_numClients--;
std::cout << "Deleting socket.\n";
sock->Destroy();
break;
}
default: ;
}
}
void MyFrame::Test(wxSocketBase *sock)
{
char buf[4096];
wxUint32 len = sock->ReadMsg(buf, sizeof(buf)).LastCount();
if ( !len )
{
std::cout << "Failed to read message.\n";
return;
}
std::cout << "Received: \"" << wxString::FromUTF8(buf, len) << "\" , Returning it\n";
sock->WriteMsg(buf, len);
}
The below message on the client happens at every 'test'. (Also when the for loop is removed.)
Input available on the socket
I searched for socket libraries, and found only 8 sort of current ones.
(Boos.ASIO, beej, bestofcpp, netlib, and others)
They were either to complicated for me to start with, or had python dependency.
I appreciate suggestions for easy to learn alternative libraries.

Related

Poco TCPServer does not start outside main

When i do the initialisation of the TCPServer inside of main it works, when i try to start it with the startServer() function it is not working, i mean i can not establish a connection with putty.
What am i doing wrong here?
Thanks for any help.
class EchoConnection : public TCPServerConnection {
public:
EchoConnection(const StreamSocket& s)
: TCPServerConnection(s) {}
void reply(char buffer[])
{
bzero(buffer, 256);
std::string myWord = "myWord\n\r";
strcpy(buffer, myWord.c_str());
}
void run() {
StreamSocket& ss = socket();
try {
char buffer[256];
int n = ss.receiveBytes(buffer, sizeof(buffer));
while (n > 0) {
reply(buffer);
ss.sendBytes(buffer, sizeof(buffer));
n = ss.receiveBytes(buffer, sizeof(buffer));
}
}
catch (Poco::Exception& exc)
{ std::cerr << "EchoConnection: " << exc.displayText() << std::endl; }
}
};
void startServer()
{
Poco::Net::TCPServer srv(new Poco::Net::TCPServerConnectionFactoryImpl<EchoConnection>, 8089);
srv.start();
SocketAddress sa("localhost", srv.socket().address().port());
StreamSocket ss(sa);
std::string data("hello, world");
ss.sendBytes(data.data(), (int)data.size());
char buffer[256] = { 0 };
int n = ss.receiveBytes(buffer, sizeof(buffer));
std::cout << std::string(buffer, n) << std::endl;
}
int main(int argc, char** argv) {
Poco::Net::TCPServer srv(new Poco::Net::TCPServerConnectionFactoryImpl<EchoConnection>, 8089);
srv.start();
SocketAddress sa("localhost", srv.socket().address().port());
StreamSocket ss(sa);
std::string data("hello, world");
ss.sendBytes(data.data(), (int)data.size());
char buffer[256] = { 0 };
int n = ss.receiveBytes(buffer, sizeof(buffer));
std::cout << std::string(buffer, n) << std::endl;
// startServer(8089);
ModuleData modData;
modData.ModuleNumber = 1;
modData.ModuleTypeId = 1;
string test = modData.serialize();
ifstream dataFile;
dataFile.open("ModuleData.dat");
if (dataFile.is_open())
{
string line;
while (getline(dataFile, line))
{
cout << line << std::endl;
}
dataFile.close();
}
while (1)
{
}
srv.stop();
}
At the end of startServer function srv object is deleted. TCPServer uses own thread but it finishes working in destructor of TCPServer.
Look at implementation of ~TCPServer
TCPServer::~TCPServer() {
try {
stop();
_pDispatcher->release();
...
}
and see stop method implementation
void TCPServer::stop() {
if (!_stopped)
{
_stopped = true; // !!
_thread.join(); // waiting for thread
_pDispatcher->stop();
}
}
the body of thread function is in run method
void TCPServer::run()
{
while (!_stopped) // this flag was set by stop method
{
... // body of thread function
}
}
stop method sets _stopped on true, and for this reason thread finishes working.

POCO - can I use SocketReactor as a client?

I see a lot of examples of SocketReactor being used in conjunction with SocketAcceptor, when people are running a TCP server.
However, i'm wanting to connect to an existing TCP server as a client, but would like to be able to handle the events exposed by SocketReactor, such as onSocketReadable, onSocketWritable, onSocketShutdown, onSocketError, and onSocketTimeout.
Is this possible with POCO libraries? I put together the following code but none of the events are triggered.
If this approach doesn't work, any other suggestions?
Basically I will be receiving a realtime stream of tcp messages from the server, and I will also send messages back to the server to perform certain tasks.
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.";
}
}
};
Can be done, but note that (a) nothing will happen until you actually run the reactor and (b) reactor will spin until explicitly stopped, so it is best to run it in separate thread;
here's a quick example:
// 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;
};
your original code, slightly modified:
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;
}
}
};
now, let's run the above:
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();
output (writable and timeout notifications silenced for clarity):
READable !!
Hello reactor world!
SHUTDOWN!!!!!!!!!!!!

ZeroMQ PUB/SUB bind subscriber

I'm studying ZeroMQ with myself.
I tested PUB as a server(bind), SUB as a client(connect) and worked fine. Opposite (PUB as a client(connect), SUB as a server(bind)) also works fine.
When I connect a another SUB socket as client something goes wrong without any exception or errors.
here's my example code.
#include <zmq.hpp>
#include <string>
#include <iostream>
#include <unistd.h>
#include <thread>
class ZMQSock
{
public:
ZMQSock(const char* addr)
{
if (addr != NULL)
{
mctx = new zmq::context_t(1);
mszAddr = new char[strlen(addr) + 1];
snprintf(mszAddr, strlen(addr) + 1, "%s", addr);
}
}
virtual ~ZMQSock()
{
if (msock != nullptr)
delete msock;
if (mctx != nullptr)
delete mctx;
if (mszAddr != nullptr)
delete [] mszAddr;
}
int zbind()
{
if (msock != nullptr)
msock->bind(mszAddr);
else return -1;
return 0;
}
int zconnect()
{
if (msock != nullptr)
msock->connect(mszAddr);
else return -1;
return 0;
}
void start()
{
if (mbthread != false)
return ;
mbthread = true;
mhthread = std::thread(std::bind(&ZMQSock::run, this));
}
virtual void stop()
{
if (mbthread == false)
return ;
mbthread = false;
if (mhthread.joinable())
mhthread.join();
}
virtual void run() = 0;
protected:
char* mszAddr{nullptr};
zmq::context_t* mctx{nullptr};
zmq::socket_t* msock{nullptr};
bool mbthread{false};
std::thread mhthread;
};
class ZPublisher : public ZMQSock
{
public:
ZPublisher(const char* addr) : ZMQSock(addr)
{
if (msock == nullptr)
{
msock = new zmq::socket_t(*mctx, ZMQ_PUB);
}
}
virtual ~ZPublisher()
{
}
bool zsend(const char* data, const unsigned int length, bool sendmore=false)
{
zmq::message_t msg(length);
memcpy(msg.data(), data, length);
if (sendmore)
return msock->send(msg, ZMQ_SNDMORE);
return msock->send(msg);
}
void run()
{
if (mszAddr == nullptr)
return ;
if (strlen(mszAddr) < 6)
return ;
const char* fdelim = "1";
const char* first = "it sends to first. two can not recv this sentence!\0";
const char* sdelim = "2";
const char* second = "it sends to second. one can not recv this sentence!\0";
while (mbthread)
{
zsend(fdelim, 1, true);
zsend(first, strlen(first));
zsend(sdelim, 1, true);
zsend(second, strlen(second));
usleep(1000 * 1000);
}
}
};
class ZSubscriber : public ZMQSock
{
public:
ZSubscriber(const char* addr) : ZMQSock(addr)
{
if (msock == nullptr)
{
msock = new zmq::socket_t(*mctx, ZMQ_SUB);
}
}
virtual ~ZSubscriber()
{
}
void setScriberDelim(const char* delim, const int length)
{
msock->setsockopt(ZMQ_SUBSCRIBE, delim, length);
mdelim = std::string(delim, length);
}
std::string zrecv()
{
zmq::message_t msg;
msock->recv(&msg);
return std::string(static_cast<char*>(msg.data()), msg.size());
}
void run()
{
if (mszAddr == nullptr)
return ;
if (strlen(mszAddr) < 6)
return ;
while (mbthread)
{
std::cout << "MY DELIM IS [" << mdelim << "] - MSG : ";
std::cout << zrecv() << std::endl;
usleep(1000 * 1000);
}
}
private:
std::string mdelim;
};
int main ()
{
ZPublisher pub("tcp://localhost:5252");
ZSubscriber sub1("tcp://localhost:5252");
ZSubscriber sub2("tcp://*:5252");
pub.zconnect();
sub1.zconnect();
sub2.zbind();
sub1.setScriberDelim("1", 1);
sub2.setScriberDelim("2", 1);
pub.start();
std::cout << "PUB Server has been started.." << std::endl;
usleep(1000 * 1000);
sub1.start();
std::cout << "SUB1 Start." << std::endl;
sub2.start();
std::cout << "SUB2 Start." << std::endl;
int i = 0;
std::cout << "< Press any key to exit program. >" << std::endl;
std::cin >> i;
std::cout << "SUB1 STOP START" << std::endl;
sub1.stop();
std::cout << "SUB2 STOP START" << std::endl;
sub2.stop();
std::cout << "PUB STOP START" << std::endl;
pub.stop();
std::cout << "ALL DONE" << std::endl;
return 0;
}
What causes this? or Am I using PUB/SUB illegally?
You are connecting a SUB socket to a SUB socket, that is an invalid connection. In your case the PUB should bind and the SUBs should connect.

XMPP Handshake Flow using Gloox C/C++

I am trying to perform XMPP Handshake Flow mentioned at https://developers.google.com/cloud-print/docs/rawxmpp.
This allows the device to subscribe and receive notifications.
As of now, I have explored the following options:
1) libcurl
2) Gloox C/C++
3) TXMPP
4) Libjingle
Which option would be a good choice to start with? I would like to consider support for and maintenance of the library as a major factor.
Following is my solution using Gloox C/C++ library to perform XMPP Handshake Flow:
#include <cassert>
#include <iostream>
#include <boost/make_shared.hpp>
#include <iq.h>
#include <parser.h>
#include <base64.h>
#include <connectiontcpclient.h>
#include <connectiontls.h>
#include <connectiondatahandler.h>
#include <connectionhttpproxy.h>
#include <logsink.h>
#include <client.h>
#include <connectionsocks5proxy.h>
using namespace gloox;
using namespace std;
const string proxyHost = ""; //specify proxy server name
const int proxyPort = 0; //specify proxy port number
const string xmppHost = "talk.google.com";
const int xmppPort = 5222;
Client *c;
ConnectionBase *client_ ;
ConnectionTCPClient* conn0;
ConnectionHTTPProxy* conn2;
class Bot: public ConnectionDataHandler, TagHandler, TLSHandler{
public:
Bot(): parser_(this)
{
conn0 = new ConnectionTCPClient(this, log_, proxyHost, proxyPort);
ConnectionHTTPProxy* conn2 = new ConnectionHTTPProxy( this, conn0, log_, xmppHost, xmppPort);
client_ = conn0;
ConnectionError ce = ConnNoError;
ce = conn2->connect();
assert(ce == ConnNoError);
conn2->receive();
}
virtual void handleConnect(const ConnectionBase* con) {
send("<stream:stream to=\"gmail.com\" xml:lang=\"en\" version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\">\r\n");
}
virtual void handleReceivedData(const ConnectionBase* con, const string& data) {
cerr << "[recv] " << data << endl;
string copied = data;
int pos = parser_.feed(copied);
assert(pos < 0);
}
virtual void handleTag(Tag* tag) {
if (tag->name() == "stream" && tag->xmlns() == "http://etherx.jabber.org/streams") {
sid_ = tag->findAttribute("id");
} else{
if (tag->name() == "features") {
if (tag->hasChild("starttls", "xmlns", "urn:ietf:params:xml:ns:xmpp-tls")) {
send(Tag("starttls", "xmlns", "urn:ietf:params:xml:ns:xmpp-tls").xml());
}
else if (tag->hasChild("mechanisms", "xmlns", "urn:ietf:params:xml:ns:xmpp-sasl") && tag->findChild("mechanisms")->hasChildWithCData(
"mechanism", "X-OAUTH2"))
{
Tag a("auth", "xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
a.addAttribute("mechanism", "X-OAUTH2");
a.addAttribute("service", "chromiumsync");
a.addAttribute("allow-generated-jid", "true");
a.addAttribute("client-uses-full-bind-result", "true");
a.addAttribute("auth", "http://www.google.com/talk/protocol/auth");
string credential;
credential.append("\0", 1);
credential.append(""); //Specify Bare JID
credential.append("\0", 1);
credential.append(""); //Specify Access Token
a.setCData(Base64::encode64(credential));
send(a.xml());
}
else if (tag->hasChild("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind")) {
Tag iq("iq", "xmlns", "jabber:client");
iq.addAttribute("type", "set");
iq.addAttribute("id", "0");
Tag *bind = new Tag("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind");
Tag *resource = new Tag("resource");
resource->setCData("GCPResource");
bind->addChild(resource);
iq.addChild(bind);
send(iq.xml());
}
}
else if (tag->name() == "proceed" && tag->xmlns() == "urn:ietf:params:xml:ns:xmpp-tls") {
ConnectionTLS* encryption_client = new ConnectionTLS(this, conn0, log_);
encryption_client->registerTLSHandler(this);
client_ = encryption_client;
ConnectionError ret = encryption_client->connect();
assert(ret == ConnNoError);
}
else if (tag->name() == "success" && tag->xmlns() == "urn:ietf:params:xml:ns:xmpp-sasl") {
send("<stream:stream to=\"gmail.com\" xml:lang=\"en\" version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\">\r\n");
}
else if (tag->name() == "iq") {
if (tag->hasChild("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind")) {
resource_ = tag->findChild("bind")->findChild("jid")->cdata();
Tag iq("iq");
iq.addAttribute("type", "set");
iq.addAttribute("id", "1");
iq.addChild(new Tag("session", "xmlns", "urn:ietf:params:xml:ns:xmpp-session"));
send(iq.xml());
//Step 2: Subscribing for notifications
if (tag->hasAttribute("type", "result")) {
Tag iq("iq");
iq.addAttribute("type", "set");
iq.addAttribute("to", ""); //Specify Bare JID
iq.addAttribute("id", "3");
Tag *bind = new Tag("subscribe", "xmlns", "google:push");
Tag *resource = new Tag("item");
resource->addAttribute("channel", "cloudprint.google.com");
resource->addAttribute("from", "cloudprint.google.com");
bind->addChild(resource);
iq.addChild(bind);
send(iq.xml());
}
}
}
}
}
virtual void handleEncryptedData(const TLSBase* tls,
const string& data) {
cout << "handleEncryptedData" << endl;
}
virtual void handleDecryptedData(const TLSBase* tls,
const string& data) {
cout << "handleDecryptedData" << endl;
}
virtual void handleHandshakeResult(const TLSBase* tls, bool,
CertInfo& cert) {
cout << "handleHandshakeResult" << endl;
}
virtual void handleDisconnect(const ConnectionBase* con, ConnectionError) {
cout << "handleDisconnect" << endl;
}
private:
LogSink log_;
string sid_;
string resource_;
Parser parser_;
ConnectionBase *client_;
void send(const string &data) {
cerr << "[send] " << data << endl;
client_->send(data);
}
};
int main() {
Bot bot;
}

Boost asio, shared_from_this() error R6010, and async_read() eof

I'm trying to make a chat with boost asio, having the officals example as reference. But i'm actually having two problems with async_read, first, why do I have an EoF(end of file) and my connexion(and application) close so quickly in the client?
And then I have a problem in the async_read of ChatParticipant : if I pass "Shared_from_this()" as second argument of boost::bind I get and error R6010, but if i pass a simple "this", I don't have it.
Thanks for your help :)
Here is my concerned code :
Chat Server
class ChatServer
{
public:
ChatServer(boost::asio::io_service& io_service, const tcp::endpoint& endpoint): _io_service(io_service), _acceptor(io_service, endpoint)
{
startAccept();
}
void startAccept()
{
std::cout << "accepting a new client" << std::endl;
shared_ptr<ServerParticipant> newParticipant(new ServerParticipant(_io_service, &_room));
_acceptor.async_accept(newParticipant->getSocket(), boost::bind(&ChatServer::handleAccept, this, boost::asio::placeholders::error, newParticipant));
}
void handleAccept(const boost::system::error_code& e, shared_ptr<ServerParticipant> newParticipant)
{
if (!e)
{
std::cout << "accepted a new client" << std::endl;
boost::asio::async_read(newParticipant->getSocket(),
boost::asio::buffer(_readMsgCache.getAllMessage(), ChatMessage::header_length),
boost::bind(&ChatServer::read, this,
boost::asio::placeholders::error));
//newParticipant->start();
startAccept();
}
else
{
std::cerr << e.message() << std::endl;
}
}
void read(const boost::system::error_code& e)
{
if (e && e == boost::asio::error::eof)
{
std::cerr << "closed" << std::endl;
}
if (e)
{
std::cerr << e.message() << std::endl;
}
else
{
std::cout << "Reaaad" << std::endl;
}
}
private:
boost::asio::io_service& _io_service;
tcp::acceptor _acceptor;
ChatMessage _readMsgCache;
}
Chat Participant
class ChatParticipant : public boost::enable_shared_from_this<ChatParticipant>
{
public :
ChatParticipant(boost::asio::io_service& service) : _id(0), _service(service), _socket(service)
{}
virtual void start()
{
startRead();
}
void startRead()
{
std::cout << "Start read" << std::endl;
boost::asio::async_read(_socket,
boost::asio::buffer(_readMsgCache.getAllMessage(), 4),
boost::bind(
&ChatParticipant::readHeader, shared_from_this(),
boost::asio::placeholders::error));
}
// some functions about decoding the message...
protected:
int _id;
boost::asio::io_service& _service;
tcp::socket _socket;
std::deque<ChatMessage> _writeMsgCache;
ChatMessage _readMsgCache;
Chat Client
using boost::asio::ip::tcp;
class ChatClient
{
public:
ChatClient(boost::asio::io_service& service, tcp::endpoint& endpoint) : _service(service), _client(service)
{
_client.getSocket().async_connect(endpoint, boost::bind(&ChatClient::handleConnect, this, boost::asio::placeholders::error));
}
void handleConnect(const boost::system::error_code& err)
{
if (err)
{
std::cerr << err.message();
}
else
{
_client.start();
/*
ChatMessage message;
message.setMessage("hello");
_client.speak(message);
*/
}
}
void read(const boost::system::error_code& e)
{
if (e)
{
std::cerr << e.message() << std::endl;
}
else
{
std::cout << "Reaaad" << std::endl;
}
}
protected :
boost::asio::io_service& _service;
ChatParticipant _client;
};
ChatMessage
#pragma once
#include <stdlib.h>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
using namespace std;
class ChatMessage
{
public :
enum{header_length = 4};
static const size_t headerLength = 4;
static const size_t maxMsgLength = 512;
ChatMessage()
{
clear();
}
void clear()
{
for (size_t i = 0; i <= maxLength() ; ++i)
_allMessage[i] = '\0';
}
char* getAllMessage()
{
return _allMessage;
}
const char* getAllMessage() const
{
return _allMessage;
}
char* getBody()
{
return _allMessage + headerLength;
}
size_t getBodyLength()
{
return _bodyLength;
}
size_t length()
{
return headerLength + _bodyLength;
}
const size_t length() const
{
return headerLength + _bodyLength;
}
size_t maxLength()
{
return headerLength + maxMsgLength;
}
bool setBody(const char* message)
{
_bodyLength = strlen(message);
if (_bodyLength > maxMsgLength)
return false;
memcpy(getBody(), message, _bodyLength);
return true;
}
bool setMessage(const char* message)
{
clear();
if (!setBody(message))
return false;
encodeHeader();
return true;
}
#pragma warning(disable: 4996) /* Disable deprecation */
bool decodeHeader()
{
char header[headerLength + 1] = "";
strncat(header, _allMessage, headerLength);
_bodyLength = atoi(header);
if (_bodyLength > maxMsgLength)
return false;
return true;
}
void encodeHeader()
{
stringstream ss;
ss << setw(headerLength) << _bodyLength;
string s(ss.str());
memcpy(_allMessage,s.c_str(), headerLength);
}
private :
char _allMessage[headerLength + maxMsgLength];
size_t _bodyLength;
};
main
#include "ChatMessage.h"
#define IsServer true
#ifdef IsServer
#include "ChatServer.h"
#else
#include "ChatCLient.h"
#endif
using boost::asio::ip::tcp;
int main()
{
boost::asio::io_service service;
#ifdef IsServer
tcp::endpoint endpoint(tcp::v4(), 13);
std::cout << "Server start" << std::endl;
ChatServer server(service, endpoint);
#else
tcp::endpoint endpoint(boost::asio::ip::address_v4::from_string("127.0.0.1"), 13);
std::cout << "Client start" << std::endl;
ChatClient client(service, endpoint);
#endif
service.run();
return 0;
}
The R6010 error is probably caused by an uncaught exception. shared_from_this() is based on a weak pointer and its operation depends upon the object being the target of a shared pointer.
That is:
shared_ptr<ChatClient> client1 (new ChatClient);
// this client can use shared_from_this()
but
ChatClient client2;
// this client cannot use shared_from_this().
change
ChatParticipant _client;
to
boost::shared_ptr<ChatParticipant> _client;
and initialize the _client pointer in the ctor initialization list. This will allow you to invoke shared_from_this() to get a shared_ptr to _client.