13h. wxWidgets – Interprocess Communications

OVERVIEW

Interprocess communication is useful when two programs need to communicate with each other. There are already existing networking protocols like TCP/IP, HTTP, FTP which enable programs to talk to each other. But in this particular case, we are only interested in the scenario where the two programs which want to communicate are on the same computer.

Though wxWidgets provides functionality for IPC (inter process communiction) to work across different computers, this post will only see how two programs residing on the same computer can talk to each other.

wxWidgets supports two kinds of IPC:

  • Windows DDE based – This is a high level protocol which is based on the Dynamic Data Exchange protocol developed for MS Windows
  • Sockets based – This is what programs running under Linux/Unix run on. They use the local network protocol to open sockets between programs.

wxWidgets provides a high layer of abstraction for IPC by internally implementing one of the two above methods based on the underlying OS and how wxWidgets has been configured. For eg.wxServer automatically uses wxDDEServer or wxTCPServer in its internal implementation.

Basically there are 3 objects which take part in IPC:

  • wxClient – program which acts as a client
  • wxServer – program which acts as a server
  • wxConnection – the actual connection class which connects clients and server. Both client and server use the same wxConnection class but implement it differently.

The sample code below consists of two different sets of programs. One for the server and one for the client. Each set consists of three objects:

  • the application loader program which loads and launches the client/server app
  • the client/server app
  • the connection app for the client/server

Both the programs run on the console and no GUI has been used in this case. You have to run the server app first and then run the client app in a separate terminal or window so that it can connect to the server. To terminate either of the two apps, press Ctrl-C

SAMPLE CODE – SERVER

ip-server-conn.h
#include  <wx/wxprec.h>
#ifndef WX_PRECOMP
	#include <wx/wx.h>
#endif
#include <wx/ipc.h>

#ifndef SERVERCONNECTION

class ServerConnection: public wxConnection {
	public:
		ServerConnection();
		~ServerConnection();
		bool OnExec (const wxString &topic, const wxString &data);
		bool OnPoke (const wxString &topic, const wxString &item, const void *data, size_t size, wxIPCFormat format);
		void const* OnRequest (const wxString &topic, const wxString &item, size_t *size, wxIPCFormat format);
		bool OnAdvise (const wxString &topic, const wxString &item, const void *data, size_t size, wxIPCFormat format);
		bool DoAdvise(const wxString& item, const void *data, size_t size, wxIPCFormat format);
		bool OnStopAdvise(const wxString& topic, const wxString& item);
		bool OnStartAdvise(const wxString& topic, const wxString& item);
		bool OnDisconnect ();

		wxString m_advise;
};
#define SERVERCONNECTION 1
#endif


ip-server-conn.cpp
#include "ip-server-conn.h"

ServerConnection::ServerConnection(void):wxConnection() { 
  wxPuts("ServerConnection() created");
}

ServerConnection::~ServerConnection(void) { 

}

bool ServerConnection::OnExec (const wxString &topic, const wxString &data) {
	 wxPuts("onExec");
	 wxPuts(topic); wxPuts(data);
	 return TRUE;

}

bool ServerConnection::OnPoke (const wxString &topic, const wxString &item, const void *data, size_t size, wxIPCFormat format) {
	 wxPuts("OnPoke");
	 return wxConnection::OnPoke(topic, item, data, size, format);

}
bool ServerConnection::OnDisconnect() {
	wxPuts("OnDisconnect");
}

void const* ServerConnection::OnRequest (const wxString &topic, const wxString &item, size_t *size, wxIPCFormat format) {
	wxPuts("onRequest");
}

bool ServerConnection::OnAdvise (const wxString &topic, const wxString &item, const void *data, size_t size, wxIPCFormat format) {
	wxPuts("onadvise");
	  m_advise = item;
    	return true;
}

bool ServerConnection::OnStartAdvise(const wxString& topic, const wxString& item)
{
    wxPuts("OnStartAdvise");
    wxPuts(topic);
    m_advise = item;
    return true;
}

bool ServerConnection::OnStopAdvise(const wxString& topic, const wxString& item)
{
    wxPuts("OnStopAdvise");
    m_advise.clear();
    return true;
}

bool ServerConnection::DoAdvise(const wxString& item, const void *data, size_t size, wxIPCFormat format)
{
    wxPuts("DoAdvise");
    return wxConnection::DoAdvise(item, data, size, format);
}




ip-server.h
#include  <wx/wxprec.h>
#ifndef WX_PRECOMP
	#include <wx/wx.h>
#endif
#include <wx/ipc.h>
#include "ip-server-conn.h"

class Server: public wxServer {
	
	public:
	    Server();
	    virtual ~Server();

	    void Disconnect();
	    bool IsConnected() { return m_connection != NULL; }
	    ServerConnection *GetConnection() { return m_connection; }

	    void Advise();
	    bool CanAdvise() { return m_connection && !m_connection->m_advise.empty(); }

	    virtual wxConnectionBase *OnAcceptConnection(const wxString& topic) wxOVERRIDE;

	protected:
	    ServerConnection *m_connection;
};


ip-server.cpp
#include "ip-server.h"
#include "ip-server-conn.h"



Server::Server() : wxServer()
{
    m_connection = NULL;
}

Server::~Server()
{
    Disconnect();
}

wxConnectionBase *Server::OnAcceptConnection(const wxString& topic)
{
    wxPrintf("OnAcceptConnection(%s)", topic);

    if ( topic == wxT("IPC TEST") )
    {
        m_connection = new ServerConnection();
        wxPuts("Connection accepted");
        return m_connection;
    }
    //else: unknown topic

    wxPuts("Unknown topic, connection refused");
    return NULL;
}

void Server::Disconnect()
{
    if ( m_connection )
    {
        wxDELETE(m_connection);
        wxPuts("Disconnected client");
    }
}

void Server::Advise()
{
    wxPuts("Advise()");
    if ( CanAdvise() )
    {
	 
        const wxDateTime now = wxDateTime::Now();

        wxString str = wxString::FromUTF8("\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82");
        m_connection->Advise(m_connection->m_advise, str + " (using UTF-8)");

        str += " (using wchar_t)";
        m_connection->Advise(m_connection->m_advise,
                             str.wc_str(), (str.length() + 1)*sizeof(wchar_t),
                             wxIPC_UNICODETEXT);

        // This one uses wxIPC_TEXT by default.
        const wxString s = now.FormatTime() + " " + now.FormatDate();
        m_connection->Advise(m_connection->m_advise, s.mb_str(), wxNO_LEN);

        char bytes[3] = { '1', '2', '3' };
        m_connection->Advise(m_connection->m_advise, bytes, 3, wxIPC_PRIVATE);
    } else 
	    wxPuts("Unable to advise");
}



ip-server-main.h
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
	#include <wx/wx.h>
#endif

class Main: public wxApp {

	public:
		virtual bool OnInit();

};
ip-server-main.cpp
#include "main.h"
#include "ip-server.h"
#include "ip-server-conn.h"
#include <wx/utils.h>
#include <wx/ipc.h>

IMPLEMENT_APP(Main)

bool Main::OnInit() {
	wxString serverName = "8000";
	Server *server = new Server();
	server->Create(serverName);
	if (!server->Create(serverName)) {
	    wxMessageBox("Failed to create server", "Client Demo Error");
	    return NULL;

	}
	return TRUE;
		
}


The sample output is given below

SAMPLE CODE – CLIENT

ip-client-conn.h
#include  <wx/wxprec.h>
#ifndef WX_PRECOMP
	#include <wx/wx.h>
#endif
#include <wx/ipc.h>

class ClientConnection: public wxConnection {
	public:
		ClientConnection();
		~ClientConnection();
		bool OnAdvise(const wxString &topic, const wxString &item, char *data, int size, wxIPCFormat format);
};

ip-client-conn.cpp
#include "ip-client-conn.h"

ClientConnection::ClientConnection(void):wxConnection() { }

ClientConnection::~ClientConnection(void) { 

}

bool ClientConnection::OnAdvise(const wxString& topic, const wxString& item, char *data,
                  int size, wxIPCFormat format)   {
        wxMessageBox(topic, data);
}
ip-client.h
#include  <wx/wxprec.h>
#ifndef WX_PRECOMP
	#include <wx/wx.h>
#endif
#include <wx/ipc.h>

class Client: public wxClient {
	
	public:
		Client();
		wxConnectionBase *OnMakeConnection();
};


ip-client.cpp
#include "ip-client.h"
#include "ip-client-conn.h"

Client::Client(void): wxClient() { }
wxConnectionBase* Client::OnMakeConnection(void)    {
        return new ClientConnection();
}
ip-client-main.h
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
	#include <wx/wx.h>
#endif

class Main: public wxApp {

	public:
		virtual bool OnInit();
};
ip-client-main.cpp
#include "main.h"
#include "ip-client.h"
#include "ip-client-conn.h"
#include <wx/utils.h>
#include <wx/ipc.h>

IMPLEMENT_APP(Main)

bool Main::OnInit() {
	wxString server = "8000";
	wxString hostName = wxT("localhost");
	Client *client = new Client();
	ClientConnection *connection = (ClientConnection *)client->MakeConnection(hostName, server, "IPC TEST");
	if (!connection)
	{
	    wxMessageBox("Failed to make connection to server", "Client Demo Error");
	    return NULL;
	}
	wxPuts("starting advise..");
	connection->StartAdvise("Item");
	wxPuts("started advise");
	wxSleep(5);
	connection->StopAdvise("Item");
	wxPuts("stopped advise");

        wxString s = "Date";

        connection->Execute(s);
	wxPuts("started execute");

	wxSleep(5);
	wxPuts("Called disconnect");

	connection->Disconnect();

	wxDELETE(client);
	wxPuts("Client object deleted");
	
	return TRUE;
}


The sample output is given below

Be the first to comment

Leave a Reply

Your email address will not be published.


*