Example: C++ TIBCO SmartSockets Application


These two C++ language example programs illustrate a simple SmartSockets application that uses the C++ class library. The first program, called sender, is a program that uses RTserver to publish a message consisting of two strings to the second program, called receiver.

Sender Program

This source listing is a program written in C++ that uses the RTserver to publish two strings in the message to another program. A discussion of the highlights follows the program example.

#include <rtworks/cxxipc.hxx> 
 
int main(int argc, char **argv) 
{ 
    // Set the name of the project  
    T_OPTION option = TutOptionLookup("project"); 
    TutOptionSetEnum(option, "ipc_example"); 
 
    // Connect to RTserver  
    TipcSrv& srv = TipcSrv::InstanceCreate(T_IPC_SRV_CONN_FULL); 
 
    // Create a message  
    TipcMsg msg(T_MT_STRING_DATA); 
    msg.Dest("/demo"); 
 
    // Build the message with two string fields: "x" and "Hello World"  
    msg << "x" << "Hello World" << Check; 
    if (!msg) { 
      TutOut("Error appending fields of TipcMsg object\n"); 
      return T_EXIT_FAILURE; 
    } 
 
    // Publish the message  
    srv.Send(msg); 
    srv.Flush(); 
    srv.Destroy(T_IPC_SRV_CONN_NONE); // force blocking close 
 
    return T_EXIT_SUCCESS; 
} // main   

The first line of the program, #include <rtworks/cxxipc.hxx>, must be included in every program that uses the SmartSockets C++ class library. It contains a series of #include’s for the various header files of the class library and is provided as a convenience to the programmer.

Moving inside the body of the main() function, the SmartSockets utility functions TutOptionLookup and TutOptionSetEnum are used to set the project name for the sender program. The receiver program uses the same project name. See the TIBCO SmartSockets User’s Guide for more information on project names.

After the project name is set, obtain a handle to a TipcSrv object and create a connection to RTserver. This is typically done with this line of code:

TipcSrv& srv = TipcSrv::InstanceCreate(T_IPC_SRV_CONN_FULL); 

Note that a TipcSrv object is not created using a constructor; instead, a reference to a TipcSrv object is returned. The TipcSrv class is designed this way because a given RTclient is only allowed to have, at most, one connection to RTserver at a time. The class library manages the construction of the TipcSrv object to encapsulate this restriction. See TipcSrv for more information about the TipcSrv class.

Following the call to TipcSrv::InstanceCreate(), a TipcMsg object is constructed by passing the T_MT_STRING_DATA message type as an argument to the constructor. The message destination is set to /demo. See the TIBCO SmartSockets User’s Guide for more information on the destination property of messages.

The next line of code in sender appends data fields to the TipcMsg object. This example illustrates a means of appending data that is unique to the C++ class library as compared to the C API. Data is appended by using overloaded insertion operators in a function chain. The function chain employs the Check manipulator to set a status flag inside of the TipcMsg object if any error occurred during the function chain’s execution. Data can also be appended using the overloaded TipcMsg::Append member function, which provides an interface similar to the C API TipcMsgAppend* functions. See Chapter 3, Messages, for more information on constructing messages.

The final step is to publish the message, which is accomplished by calling the TipcSrv member functions TipcSrv::Send(), TipcSrv::Flush(), and TipcSrv::Destroy(). See TipcSrv for more information about the TipcSrv class.

Receiver Program

This source listing is a program written in C++ that uses the RTserver to receive two strings in the message from another program. After the listing is a brief discussion of some program highlights.

#include <rtworks/cxxipc.hxx> 
 
int main(int argc, char **argv) 
{ 
  // Set the name of the project  
  T_OPTION option = TutOptionLookup("project"); 
  TutOptionSetEnum(option, "ipc_example"); 
 
  // Connect to RTserver  
  TipcSrv& srv = TipcSrv::InstanceCreate(T_IPC_SRV_CONN_FULL); 
   
  // Subscribe to receive any messages published to the "/demo" 
  // subject 
  srv.SubjectSubscribe("/demo", TRUE); 
 
  // Get the next incoming message 
  TipcMsg msg(srv.Next(T_TIMEOUT_FOREVER)); 
  if (!srv) { 
      TutOut("Error creating TipcMsg object\n"); 
      return T_EXIT_FAILURE; 
  } 
  // Set the pointer to first field in message 
  msg.Current(0); 
 
  T_STR var_name; 
  T_STR var_value; 
 
  // Extract the information from the received message 
  msg >> var_name >> var_value >> Check; 
  if (!msg) { 
      TutOut("Error reading fields of TipcMsg object\n"); 
      return T_EXIT_FAILURE; 
  } 
   
  // Display the values on stdout 
  TutOut("Variable Name  = %s\n", var_name); 
  TutOut("Variable Value = %s\n", var_value); 
  srv.Destroy(T_IPC_SRV_CONN_NONE); // force blocking close 
 
  return T_EXIT_SUCCESS; 
} // main   

The first line of the program is #include <rtworks/cxxipc.hxx> just as it was in the sender program earlier. Inside the main function, the same C API calls are also used to set the project name option and create the connection to RTserver.

The receiver program next subscribes to the appropriate subject, /demo, by calling the TipcSrv::SubjectSubscribe member function. Note that the sender program designated /demo as the destination of the message. See the TIBCO SmartSockets User’s Guide for information regarding subjects in RTclient.

At this point, the receiver waits for a message from RTserver. This is done by calling the TipcSrv::Next member function using T_TIMEOUT_FOREVER as the argument to the call. The result of the Next member function is either a T_IPC_MSG or a NULL. This value is passed to the TipcMsg constructor for the msg object. If the TipcMsg constructor is passed a NULL, then the internal status of the object is set to FALSE. The status of the msg object is queried with operator!(). See TipcMsg on page 110 for more details on the TipcMsg class.

After the receiver program receives a message from RTserver, the data fields are extracted from the message. The first step in the extraction is to set the current field of the message to the first field by using the TipcMsg::Current member function. Next, the actual data is extracted in a C++ function chain of overloaded extraction operators. As with the insertion function chain used in the sender to append data fields to a message, the extraction function chain employs the Check manipulator to set a status flag inside of the TipcMsg object if any error occurred during the function chain’s execution. Data are also extracted using the overloaded TipcMsg::Next member functions, which provide an interface similar to the C API TipcMsgNext* functions. See Chapter 3, Messages, for more information on extracting data fields from TipcMsg objects.

Finally, the program outputs the values of the data fields by outputting the data using the TutOut function calls. Note that this example avoids using cout from IOSTREAM. The reason for this is that some SmartSockets functions use TutOut to display status information. Because TutOut uses the stdout stream and cout typically uses its own output stream, it is recommended that TutOut be used in RTclient programs, rather than cout, so that output is printed in sequential order.

Compiling, Linking, and Running

To compile, link, and run the example programs, first you must either copy the programs to your own directory or have write permission in this directory:

UNIX:
$RTHOME/examples/cxxipc 
OpenVMS:
RTHOME:[EXAMPLES.CXXIPC] 
Windows:
%RTHOME%\examples\cxxipc 

Use these commands to compile and link the programs:

UNIX:
$ rtlink -cxx -o sndr.x sndr.cxx 
$ rtlink -cxx -o rcvr.x rcvr.cxx 
OpenVMS:
$ cxx sndr.cxx 
$ cxx rcvr.cxx 
$ rtlink -cxx /exec=sndr.exe sndr.obj 
$ rtlink -cxx /exec=rcvr.exe rcvr.obj 
Windows:
$ nmake /f sndrw32m.mak 
$ nmake /f rcvrw32m.mak 

On a UNIX system the rtlink command by default uses the C compiler cc command to compile and link. Specifying the -cxx flag tells rtlink to use the native C++ compiler (for example, on a Solaris platform the compiler is named CC, on AIX xlC, on Digital UNIX cxx, and so on) and adds the SmartSockets C++ class library to the list of libraries to be linked into the executable. To use a C++ compiler other than the default compiler, set the environment variable CC to the name of the compiler. rtlink then uses this compiler.

For example, these commands are used to compile and link on UNIX with the GNU C++ compiler g++:

UNIX:
$ env CC=g++ rtlink -cxx -o sndr.x sndr.cxx 
$ env CC=g++ rtlink -cxx -o rcvr.x rcvr.cxx 

Start RTserver before you run the program. Use this command to start RTserver:

$ rtserver 

On platforms that support both 32- and 64-bit, use the rtserver64 command to run the 64-bit version of the rtserver script.

To run the programs, start the receiving process first in one terminal emulator window and then the sending process in another terminal emulator window.

Start up the receiving program in the first window:

UNIX:
$ rcvr.x 
OpenVMS:
$ run rcvr.exe 
Windows:
$ rcvr.exe 

Start up the sending program in the second window:

UNIX:
$ sndr.x 
OpenVMS:
$ run sndr.exe 
Windows:
$ sndr.exe  

The output from the receiving process is similar to this:

Connecting to project <ipc_example> on <_node> RTserver. 
Using local protocol. 
Message from RTserver: Connection established. 
Start subscribing to subject </_workstation1_6605>. 
Variable Name  = x 
Variable Value = Hello World 

The output from the sending process is similar to this:

Connecting to project <ipc_example> on <_node> RTserver. 
Using local protocol. 
Message from RTserver: Connection established. 
Start subscribing to subject </_workstation1_6607>. 

TIBCO SmartSockets™ cxxipc Class Library
Software Release 6.8, July 2006
Copyright © TIBCO Software Inc. All rights reserved
www.tibco.com