This section discusses how to create, access, and destroy connections. Because the focus of this chapter is on the publish-subscribe model, the connections that we describe are usually between the RTclient and an RTserver. To learn more about working with connections in general, see Chapter 2, Connections. The following example programs show the publish-subscribe code used to publish a small data frame of messages, including a user-defined message type, between two RTclients through RTserver. The programs also show how to work with subjects. There are two parts to the example: a sending RTclient and a receiving RTclient. An RTclient can both send messages to and receive messages from RTserver, but this example only shows the two processes doing one or the other. This example only shows a few of the publish-subscribe features built on top of connections.
The source code files for this example are located in the following directory:
The online source files have additional #ifdefs
to provide C++ support; these #ifdefs
are not shown to simplify the example.
/* rtclient.h -- common header for RTclient examples */
#define EXAMPLE_PROJECT "example" #define EXAMPLE_SUBJECT "rcv" #define EXAMPLE_MT_NAME "example_mt" #define EXAMPLE_MT_NUM 42 #define EXAMPLE_MT_GRAMMAR "int4 /*code*/ str /*explanation*/" void create_ud_msg_types();
/* rtclutil.c -- RTclient example utilities */
#include <rtworks/ipc.h> #include "rtclient.h"/* =============================================================== */
/*..create_ud_msg_types -- create example user-defined msg types */
void create_ud_msg_types() { T_IPC_MT mt; /* Create our user-defined message type. */ mt = TipcMtCreate(EXAMPLE_MT_NAME, EXAMPLE_MT_NUM, EXAMPLE_MT_GRAMMAR); if (mt == NULL) { TutOut("Could not create example message type: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); }/* Add the new message type to the DATA logging category. */
if (!TipcSrvLogAddMt(T_IPC_SRV_LOG_DATA, mt)) { TutOut("Could not add example mt to DATA category: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } }/* create_ud_msg_types */
/* rtclrcv.c -- RTclient example receiver */
/* The receiving RTclient creates its connection to RTserver, */
/* subscribes to subjects, and receives and processes messages. */
#include <rtworks/ipc.h> #include "rtclient.h"/* =============================================================== */
/*..cb_process_numeric_data -- process callback for NUMERIC_DATA */
static void T_ENTRY cb_process_numeric_data( T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg) { T_STR name; T_REAL8 value; TutOut("Entering cb_process_numeric_data.\n");/* set current field to first field in message */
if (!TipcMsgSetCurrent(data->msg, 0)) { TutOut("Could not set current field of message: error <%s>.\n", TutErrStrGet()); return; }/* access and print fields */
while (TipcMsgNextStrReal8(data->msg, &name, &value)) { TutOut("%s = %s\n", name, TutRealToStr(value)); }/* make sure we reached the end of the message */
if (TutErrNumGet() != T_ERR_MSG_EOM) { TutOut("Did not reach end of message: error <%s>.\n", TutErrStrGet()); } }/* cb_process_numeric_data */
/* =============================================================== */
/*..cb_default -- default callback */
static void T_ENTRY cb_default( T_IPC_CONN conn, T_IPC_CONN_DEFAULT_CB_DATA data, T_CB_ARG arg) { T_IPC_MT mt; T_STR name;/* This callback function will be called for messages where */
/* there are no process callbacks for that message type. */
TutOut("Entering cb_default.\n");/* print out the name of the type of the message */
if (!TipcMsgGetType(data->msg, &mt)) { TutOut("Could not get message type from message: error <%s>.\n", TutErrStrGet()); return; } if (!TipcMtGetName(mt, &name)) { TutOut("Could not get name from message type: error <%s>.\n", TutErrStrGet()); return; } TutOut("Message type name is %s.\n", name); }/* cb_default */
/* =============================================================== */
/*..main -- main program */
int main(argc, argv) int argc; char **argv; { T_OPTION option; T_IPC_MT mt;/* message type for creating callbacks */
/* Create user-defined message types. */
create_ud_msg_types();/* Set the option Project to partition ourself. */
option = TutOptionLookup("project"); if (option == NULL) { TutOut("Could not look up option named project: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } if (!TutOptionSetEnum(option, EXAMPLE_PROJECT)) { TutOut("Could not set option named project: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); }/* Allow a command-line argument containing the name of a */
/* SmartSockets startup command file. This file can be used */
/* to set options like Server_Names. */
if (argc == 2) { if (!TutCommandParseFile(argv[1])) { TutOut("Could not parse startup command file %s: error <%s>.\n", argv[1], TutErrStrGet()); TutExit(T_EXIT_FAILURE); } } else if (argc != 1) {/* too many command-line arguments */
TutOut("Usage: %s [ command_file_name ]\n", argv[0]); TutExit(T_EXIT_FAILURE); } TutOut("Creating connection to RTserver.\n"); if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { TutOut("Could not create connection to RTserver: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); }/* create callbacks to be executed when certain operations occur */
TutOut("Create callbacks.\n");/* process callback for NUMERIC_DATA */
mt = TipcMtLookupByNum(T_MT_NUMERIC_DATA); if (mt == NULL) { TutOut("Could not look up NUMERIC_DATA msg type: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } if (TipcSrvProcessCbCreate(mt, cb_process_numeric_data, NULL) == NULL) { TutOut("Could not create NUMERIC_DATA process cb: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); }/* default callback */
if (TipcSrvDefaultCbCreate(cb_default, NULL) == NULL) { TutOut("Could not create default cb: error <%s>.\n", TutErrStrGet()); } TutOut("Start subscribing to standard subjects.\n"); if (!TipcSrvStdSubjectSetSubscribe(TRUE, FALSE)) { TutOut("Could not subscribe to standard subjects: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } TutOut("Start subscribing to the %s subject.\n", EXAMPLE_SUBJECT); if (!TipcSrvSubjectSetSubscribe(EXAMPLE_SUBJECT, TRUE)) { TutOut("Could not start subscribing to %s subject: error <%s>.\n", EXAMPLE_SUBJECT, TutErrStrGet()); TutExit(T_EXIT_FAILURE); }/* If an error occurs, then TipcSrvMainLoop will restart RTserver */
/* and return FALSE. We can safely continue. */
for (;;) { if (!TipcSrvMainLoop(T_TIMEOUT_FOREVER)) { TutOut("TipcSrvMainLoop failed: error <%s>.\n", TutErrStrGet()); } }/* This line should not be reached. */
TutOut("This line should not be reached!!!\n"); return T_EXIT_FAILURE; }/* main */
/
* rtclsnd.c -- RTclient example sender */
/*
This sending RTclient creates its connection and publishes a data frame of messages to a subject (through RTserver).
*/
#include <rtworks/ipc.h> #include "rtclient.h"/* =============================================================== */
/*..main -- main program */
int main(argc, argv) int argc; char **argv; { T_OPTION option; T_IPC_MT mt;/* Create user-defined message types. */
create_ud_msg_types();/* Set the option Project to partition ourself. */
option = TutOptionLookup("project"); if (option == NULL) { TutOut("Could not look up option named project: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } if (!TutOptionSetEnum(option, EXAMPLE_PROJECT)) { TutOut("Could not set option named project: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); }/* Log outgoing data messages to a message file. Another */
/* way to set options is to use TutCommandParseStr. */
TutCommandParseStr("setopt log_out_data log_out.msg");/* Allow a command-line argument containing the name of a */
/* SmartSockets startup command file. This file can be used */
/* to set options like Server_Names. */
if (argc == 2) { if (!TutCommandParseFile(argv[1])) { TutOut("Could not parse startup command file %s: error <%s>.\n", argv[1], TutErrStrGet()); TutExit(T_EXIT_FAILURE); } } else if (argc != 1) {/* too many command-line arguments */
TutOut("Usage: %s [ command_file_name ]\n", argv[0]); TutExit(T_EXIT_FAILURE); } TutOut("Creating connection to RTserver.\n"); if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { TutOut("Could not create connection to RTserver: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } TutOut("Publish a frame of data to the receiver’s subject.\n"); TutOut("Publishing a TIME message.\n"); mt = TipcMtLookupByNum(T_MT_TIME); if (mt == NULL) { TutOut("Could not look up TIME msg type: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } if (!TipcSrvMsgWrite(EXAMPLE_SUBJECT, mt, TRUE, T_IPC_FT_REAL8, 1.0, NULL)) { TutOut("Could not publish TIME message: error <%s>.\n", TutErrStrGet()); } TutOut("Publishing a NUMERIC_DATA message.\n"); mt = TipcMtLookupByNum(T_MT_NUMERIC_DATA); if (mt == NULL) { TutOut("Could not look up NUMERIC_DATA msg type: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } if (!TipcSrvMsgWrite(EXAMPLE_SUBJECT, mt, TRUE, T_IPC_FT_STR, "voltage", T_IPC_FT_REAL8, 33.4534, T_IPC_FT_STR, "switch_pos", T_IPC_FT_REAL8, 0.0, NULL)) { TutOut("Could not publish NUMERIC_DATA message: error <%s>.\n", TutErrStrGet()); } TutOut("Publishing an EXAMPLE message.\n"); mt = TipcMtLookupByNum(EXAMPLE_MT_NUM); if (mt == NULL) { TutOut("Could not look up EXAMPLE msg type: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } if (!TipcSrvMsgWrite(EXAMPLE_SUBJECT, mt, TRUE, T_IPC_FT_INT4, 7, T_IPC_FT_STR, "Seven is your lucky number", NULL)) { TutOut("Could not publish EXAMPLE message: error <%s>.\n", TutErrStrGet()); } TutOut("Publishing an END_OF_FRAME message.\n"); mt = TipcMtLookupByNum(T_MT_END_OF_FRAME); if (mt == NULL) { TutOut("Could not look up END_OF_FRAME msg type: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } if (!TipcSrvMsgWrite(EXAMPLE_SUBJECT, mt, TRUE, NULL)) { TutOut("Could not publish END_OF_FRAME message: error <%s>.\n", TutErrStrGet()); }/* Each RTclient automatically creates a connection process */
/* callback for CONTROL messages. Use this to send the command */
/* "quit force" to the receiver’s command interface. */
TutOut("Publishing a CONTROL message to stop the receiver(s).\n"); mt = TipcMtLookupByNum(T_MT_CONTROL); if (mt == NULL) { TutOut("Could not look up CONTROL msg type: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } if (!TipcSrvMsgWrite(EXAMPLE_SUBJECT, mt, TRUE, T_IPC_FT_STR, "quit force", NULL)) { TutOut("Could not publish CONTROL message: error <%s>.\n", TutErrStrGet()); }/* Flush the buffered outgoing messages to RTserver. */
if (!TipcSrvFlush()) { TutOut("Could not flush messages to RTserver: error <%s>.\n", TutErrStrGet()); }/* Completely disconnect from RTserver. */
if (!TipcSrvDestroy(T_IPC_SRV_CONN_NONE)) { TutOut("Could not destroy connection to RTserver: error <%s>.\n", TutErrStrGet()); } TutOut("Sender RTclient exiting successfully.\n"); return T_EXIT_SUCCESS;/* all done */
}/* main */
To compile, link, and run the example programs, first you must either copy the programs to your own directory or have write permission in the following directory or partitioned datasets (MVS):
To compile and link the programs, use:
$ cc rtclrcv.c, rtclsnd.c, rtclutil.c $ rtlink /exec=rtclrcv.exe rtclrcv.obj, rtclutil.obj $ rtlink /exec=rtclsnd.exe rtclsnd.obj, rtclutil.obj
On UNIX the rtlink
command by default uses the cc
command to compile and link. To use a C++ compiler or a C compiler with a name other than cc
, set the environment variable CC
to the name of the compiler, and rtlink
then uses this compiler. For example, these commands could be used to compile and link on UNIX with the GNU C++ compiler g++
:
$ env CC=g++ rtlink -o rtclrcv.x rtclrcv.c rtclutil.c $ env CC=g++ rtlink -o rtclsnd.x rtclsnd.c rtclutil.c
Start RTserver
Before running the programs, start RTserver. An RTclient will not by default automatically start an RTserver. You can change this behavior by using a start prefix in RTclient’s Server_Names option. For more information, see Start Prefix and Starting and Stopping RTserver.
Use this command to start RTserver on 32-bit platforms:
To run the programs, start the receiving process first in one terminal emulator window and then the sending process in another terminal emulator window.
![]() |
On platforms that support both 32- and 64-bit, use the rtserver64 command to run the 64-bit version of RTserver.
|
Start the receiving program in the first window
Start the sending program in the second window
Here is an example of the receiving process output:
Creating connection to RTserver. Connecting to project <example> on <_node> RTserver Using local protocol Message from RTserver: Connection established. Start subscribing to subject </_node
_5415> Create callbacks. Start subscribing to standard subjects. Start subscribing to subject </_node
> Start subscribing to subject </_all> Start subscribing to the rcv subject. Entering cb_default. Message type name is time. Entering cb_process_numeric_data. voltage = 33.4534 switch_pos = 0 Entering cb_default. Message type name is example_mt. Entering cb_default. Message type name is end_of_frame.
Here is an example of the sending process output:
Now logging outgoing data-related messages to <log_out.msg>
Creating connection to RTserver.
Connecting to project <example> on <_node> RTserver
Using local protocol
Message from RTserver: Connection established.
Start subscribing to subject </_node
_5415>
Publish a frame of data to the receiver’s subject.
Publishing a TIME message.
Publishing a NUMERIC_DATA message.
Publishing an EXAMPLE message.
Publishing an END_OF_FRAME message.
Publishing a CONTROL message to stop the receiver(s).
Now logging outgoing data - related messages to <log_out.msg>
Sender RTclient exiting successfully.
The message file log_out.msg
, which is created by the sender:
time rcv 1 numeric_data rcv { voltage 33.4534 switch_pos 0 } example_mt rcv 7 "Seven is your lucky number" end_of_frame rcv control rcv "quit force"
More than one receiving process can be started if desired. Each receiving process receives the same messages from the sending process. To run three receivers, start the receiving program in three separate windows or in batch (background), using the same command as shown in Step 3.
Code written in C or C++ that uses the SmartSockets Application Programming Interface (API) must include the header file <rtworks/ipc.h>
. This file is located in these directories or partitioned datasets (MVS):
The SmartSockets IPC API includes all the functions used for interprocess communication.
Most TipcConn* connection functions have an equivalent TipcSrv* function that operates only on the connection to RTserver. For most TipcConn* functions that have a TipcSrv* equivalent, the calling sequences are identical except that the T_IPC_CONN first parameter in the TipcConn* function disappears in the TipcSrv* function because the connection is always with RTserver. For example, the C/C++ function prototype for TipcConnMsgProcess is:
The corresponding function prototype for TipcSrvMsgProcess is:
Table 6 shows the TipcSrv* functions that have names similar to TipcConn* functions, but that have different behavior.
Table 7 shows the TipcConn* functions that do not have TipcSrv* equivalents.
Table 8 shows the TipcSrv* functions that do not have TipcConn* equivalents.
Options allow you to customize your RTclient’s configuration. A user-defined RTclient does not have any standard startup command files. It is up to you to decide which command files, if any, should be loaded. Startup command files can be loaded with the function TutCommandParseStr or by using TutCommandParseFile. Options can also be set using the function TutOptionSetType
, where Type
is replaced with the type of the option. All RTclient options are discussed in detail in Chapter 8, Options Reference.
After an RTclient has initialized its options, a connection to RTserver can be created. There are two kinds of global connections to RTserver: a warm connection and a full connection. Warm connections are discussed in Warm Connection to RTserver. Through the remainder of this document, the term connection to RTserver is used to mean a full global connection to RTserver.
The function TipcSrvCreate is used to create a connection to RTserver. For example:
if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { TutOut("Could not create connection to RTserver: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); }
The connect
command provides a way to use TipcSrvCreate from the SmartSockets command interface (see the command reference for connect
).
An RTclient cannot have a global connection to more than one RTserver at a time, although it can move its connection from one RTserver to another RTserver at any time. However, instead of a single global connection, an RTclient can have multiple RTserver connections using a special type of multiple connection. For more information in C, see Connecting to Multiple RTservers. For more information in Java, see the TIBCO SmartSockets Java Library User’s Guide and Tutorial.
TipcSrvCreate uses several options to control the creation of the connection to RTserver:
The options Default_Subject_Prefix, Project, Server_Disconnect_Mode, and Unique_Subject do not directly control connecting to RTserver, but they are used once RTclient has found an RTserver.
If the SmartSockets system is enabled for multicast and the RTclient wants to use multicast, the RTclient must connect to an RTgms instead of connecting to an RTserver. In most cases, the only change required is to the Group_Names and Server_Names options in the RTclient command (.cm
) file.
The Group_Names option specifies which multicast group the RTclient belongs to. The default is rtworks
, and you only need to change the value if you are not using that group name.
The Server_Names option must provide the logical connection name for an RTgms process instead of the logical connection name for an RTserver process.
For example, your RTclient command file might contain:
Let’s assume the RTclient should belong to the multicast group mcast1
, and should connect to the RTgms on nodea
using the default port, which is 5104. Change the lines to:
If you want to connect to an RTgms that is not using the default port, change the Server_Names line to:
which connects to the RTgms on nodea
using port 6000. For more information on the format of RTgms addresses, see Address for Multicast.
After ensuring your options are set correctly for multicast, use the function TipcSrvCreate to connect to the RTgms process the same way you connect to an RTserver process:
if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { TutOut("Could not create connection to RTgms: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); }
When connecting to an RTgms process, you cannot specify pgm:localhost
alone. You must also include TCP as the protocol:
In addition to the options used in creating connections for an RTclient, there are special options that apply only to multicast connections. The names of these options begin with Pgm_. These options must be set in a multicast command file, mcast.cm
. For information on these options and on the multicast command file, see Chapter 10, Using Multicast. If your SmartSockets system does not have the multicast option installed, you receive an error when you attempt to connect to RTgms.
When an RTclient creates a connection to RTserver, it becomes part of the project named in the option Project. As described in Projects, each project is self-contained, and no messages can be sent between projects.
SmartSockets RT processes, such as RTserver and RTclient, simplify the creation of connections with logical connection names that are specified consistently for all protocols. RTserver and RTclient take full advantage of the logical connection name feature of connections. For an introduction to these features, see the section Logical Connection Names. RTserver uses logical connection names to create its connections, and RTclient uses logical connection names to create a client connection to an RTserver or RTgms.
The most important option for connecting to another RT process is Server_Names, which is used to find and start an RT process such as RTserver. Server_Names is a list of logical connection names. Each logical connection name has the form:
which can be shortened to protocol
:node
, protocol
, or simply node
for normal connections. The TipcSrvCreate function expands the shortened forms to the long protocol
:node
:address
form and uses default values for the parts that are not specified. For RTclient to find an RTserver, one of the logical connection names used by RTclient must exactly match one of the logical connection names used by that RTserver (for example, the name tcp:abc:1234
does not match the name tcp:xyz:1234
).
For RTclient to automatically start or re-start an RTserver, Server_Names must use one of the start prefixes listed in Start Prefix. By default, the start prefix is start_never
, meaning that RTclient cannot start RTserver.
The protocol
part of the connection name refers to an IPC protocol type. Examples of common protocols are tcp
, local
. There is also the special SmartSockets protocol defined for multicast, pgm
. The pgm
protocol is only supported if your SmartSockets system has the multicast option installed.
If protocol
is omitted from the connection name, then all protocols listed in the Default_Protocols option are tried in order. These protocol names (with the exception of udp_broadcast
, which is described in the next section) map to the TipcConnCreateClient function described in the section Creating a Client Connection.
If you specify pgm
for multicast as the protocol, the address portion of the logical connection name uses a different format than for other protocols. See Address for Multicast.
The udp_broadcast
protocol is only used to find RTserver, and not to start RTserver or send or receive messages. When the udp_broadcast
protocol is used, a packet is broadcast to all nodes on the local network to attempt to find an RTserver. If an RTserver receives the broadcast packet, it responds to the request with a list of logical connection names for RTclient to use to find that RTserver. RTclient waits the number of seconds specified in the Udp_Broadcast_Timeout option for RTserver to respond to its broadcast, and then connects to the RTserver that responds first.
There are several categories of UDP broadcast addresses that vary in how wide an area they are distributed over. The book TCP/IP Illustrated, Volume 1: The Protocols by W. Richard Stevens has an excellent discussion of broadcasting. The categories are shown below.
Unfortunately, these categories behave differently depending on the operating system and network router configuration used, making it hard to pick a default broadcast address that works in all situations. The limited and all-subnets-directed broadcast addresses do not work on several operating systems supported by SmartSockets.
Therefore, by default the broadcast packet is sent to the subnet-directed address of the main network interface. In non-subnetted networks, the net-directed, subnet-directed, and all-subnet-directed broadcast addresses are equivalent, which makes the subnet-directed address the most reasonable default for most networks.
When using the udp_broadcast
protocol, a dotted-decimal address can be used for the node portion of the logical connection name to override the broadcast default. For example, the logical connection name udp_broadcast:255.255.255.255
can be used on many platforms as a limited broadcast address.
The node
part of the connection name refers to a computer node name. If node
is omitted from the connection name, then _node,
the current node, is used as a default. Using the default node works if your RTserver or RTgms process to which you are connecting is on the same node as your RTclient. If you configured them to be on a different node, you must specify that node for the node
portion of the connection name.
The address
part of the connection name refers to a protocol-specific IPC location, such as a tcp
port number. If address
is omitted from the connection name, a protocol-specific default address
is used. The default addresses for all protocols are:
Protocol Name
|
Default Address
|
---|---|
local
|
RTSERVER
|
pgm
|
unicast_protocol.address
(See Address for Multicast.)
|
tcp
|
5101
|
udp_broadcast
|
5101
|
If you are connecting to an RTgms process for multicast, instead of to an RTserver, the address portion of your logical connection name is a different format than for other protocols. The format for multicast is:
where:
If you specify a multicast format address, and your SmartSockets system does not have the multicast option installed, you receive an error when you attempt to connect to RTgms.
Each logical connection name in RTclient can also have a logical connection name modifier called a start prefix at the front, which must be separated from the name with a colon:
For more information, see Logical Connection Name Modifiers.
The start prefix controls if and when an RTclient tries to start RTserver. On Windows, if an RTserver has been installed as a Windows service, you must also set the proper environment variable before an RTclient can use a start prefix to start that RTserver. Set the RTSERVER_CMD environment variable to:
The valid start prefixes are:
start_always
|
RTclient always tries to start RTserver if it cannot create the connection to RTserver.
|
start_on_demand
|
RTclient only tries to start RTserver if the RTclient has tried all names in Server_Names at least once. This is useful for only starting RTserver if an existing one cannot be found. For this start prefix to be used, the Server_Start_Max_Tries option must be increased above the default value of 1 (see pseudo code in Finding and Starting RTserver for details).
|
start_never
|
RTclient never tries to start RTserver. This is the default.
|
If no start prefix is specified, an implicit default start prefix of start_never
is used. If the protocol
portion of the logical connection name is local
and the node
portion is not the name of the current node, an implicit start prefix of start_never
is used because the local protocol cannot connect to a remote RTserver.
![]() |
The start prefix is only for an RTclient to start an RTserver. It cannot be used by any other process to start an RTserver or used by an RTclient to start a process other than an RTserver.
|
The special value _random
can be used in the Server_Names option in an RTclient to randomize the list of RTserver names. Every name occurring after _random
is tried in a random order. This enables load balancing of the RTclient connections to the associated RTservers. For example, if the option Server_Names is set to workstation1, _random, workstation2, workstation3, workstation4
, then workstation1
is always tried first, and then workstation2
, workstation3
, and workstation4
are tried in a random order each call to the TipcSrvCreate function.
The special value _next
can be used in the server_names
option for an RTclient. This special value changes the starting point at which the RTclient traverses the server_names
option in the event of server failure. If included, the _next
value must be the first value presented in the server_names
list. Each server name is tried in sequential order, starting with the "next" server listed after the currently connected server. This prevents the RTclient from attempting to reconnect to a server to which it had previously lost its connection.
For example:
When the RTclient initially tries to make a connection to a server, it attempts to connect to server1
. Once a connection is established to server1
, should a failure occur in server1
, the RTclient attempts reconnection by starting with the "next" server in the list, server2
. Without the _next
property, the RTclient would always attempt to connect to the list of servers starting with the first server in the list. The _next
option does not eliminate any servers from the list; if the RTclient reaches the end of the list when using the _next
option, then the RTclient circles back around to the front of the list and continues connection attempts until all servers in the list have been attempted.
Generally, for an RTclient to find an RTserver, the logical connection name used in Server_Names by the RTclient must exactly match the logical connection name used in Conn_Names by the RTserver. For example, the name tcp:moe:1234
does not match the name tcp:conan:1234
. However, this perfect match is not needed when the RTclient is trying to find an RT server that is listening on all IP addresses on a machine with more than one IP address, that is, multi-homed.
An RTserver listens on all IP addresses of a machine if the node
portion of its logical connection name (specified in Conn_Names) is _any
. Using _node
for node
causes the RTserver to listen only on the default IP address. For example, if an RTserver is on a machine with IP addresses ipaddr_a
and ipaddr_b
, and its Conn_Names is set to tcp:_any:5101
, an RTclient can connect to this RTserver if its Server_Names option is set to either tcp:ipaddr_a:5101
or tcp:ipaddr_b:5101
.
If you want the RTserver to listen only on a specific IP address, you can specify that IP address in the Conn_Names option. However, there is a known issue that occurs if running an RTserver on a machine with multiple IP addresses when using udp_broadcast
to discover RTservers. Any responding RTserver replies with only its default IP address, even if its Conn_Names option is specifically set to listen on an IP address other than the default. If you are using udp_broadcast
, be sure to include the default IP address in the RTserver Conn_Names option, or use _node
or _any
in the Conn_Names option.
![]() |
Using the keyword
_any in Conn_Names is discouraged for RTserver to RTserver connections. When an RTserver connects to another RTserver whose Conn_Names use _any , the RTserver might attempt to reconnect every Server_Reconnect_Interval seconds. This is a known problem and will be fixed in a future release.
|
An RTclient traverses the list of names in Server_Names at most Server_Start_Max_Tries. Between each traversal RTclient sleeps for Server_Start_Delay seconds. Each time an RTclient tries to start RTserver, it waits for up to Server_Start_Timeout seconds for that RTserver to finish initializing. For each entry in Server_Names, RTclient tries to connect, then possibly tries to start RTserver (depending on what start prefix is used), then tries to connect again.
There is a server names traverse callback available to RTclients. This callback is executed before each attempt to connect to an RTserver in the Server_Names list. For more information, see Server Names Traverse Callbacks.
This pseudo code shows the algorithm used by TipcSrvCreate:
randomize Server_Names list if _random is used for (each $try from 1 to Server_Start_Max_Tries) { for (each $name in Server_Names) { connect to RTserver using $name if (connection could be created) { if (no connection previously existed) { resend old GMD messages } execute server create callbacks return } else { if ($name has the start prefix "start_always" or $name has no start prefix or ($name has the start prefix "start_on_demand" and $try > 1)) { start RTserver with command "rtserver -nodenode
" wait up to Server_Start_Timeout seconds for RTserver to init connect to RTserver using $name if (connection could be created) { if (no connection previously existed) { resend old GMD messages } execute server create callbacks return } }/* if we should try to start RTserver */
}/* if no connection */
}/* for each name */
sleep for Server_Start_Delay seconds }/* for each try */
![]() |
The start_on_demand start prefix only starts RTserver if the option Server_Start_Max_Tries is set to a value larger than 1 (the default).
|
If TipcSrvCreate is able to successfully create a connection, it calls the server create callbacks (see RTclient-Specific Callbacks for information on server create callbacks).
The options shown in the example are only accessed when the RTclient creates a connection to RTserver. If one of these options is changed, it does not take effect until the next time the RTclient creates a connection to RTserver. See Changing RTclient Options for an example of how to change these options and have them take effect immediately.
When RTclient starts RTserver, it uses the node
portion of the logical connection name to determine which node to attempt to start RTserver on. To start RTserver on a remote node, it must be possible to perform a remote shell rsh
(remsh
on HP-UX) to that node without a password. If rsh
to the remote system does not work, then the RTclient is not able to start RTserver. Use this command to test rsh
(on all platforms except HP-UX):
On HP-UX, use this command:
![]() |
On platforms that support both 32- and 64-bit, use the rtserver64 command to run the 64-bit version of RTserver.
|
If a prompt for a password appears when this command is entered, contact the system administrator for help in configuring the remote shell (rsh or remsh) to not require a password.
Starting RTserver on a remote machine under OpenVMS requires a TCP/IP package running with support for the rsh
command, such as MultiNet.
Occasionally, you may find that RTclient can no longer connect to RTserver using the local
protocol, but can still connect using the TCP protocol. For example:
Connecting to project <rtworks> on <_node> RTserver. Using local protocol. connect: No such file or directory Could not connect to <_node> RTserver. Connecting to project <rtworks> on <_node> RTserver. Using tcp protocol. Message from RTserver: Connection established.
One possible scenario is the local
socket file used by RTserver (stored in the directory specified by the function TutGetSocketDir) gets deleted somehow, perhaps by an overzealous system administrator. To fix the problem, simply restart RTserver, and a new socket file is created.
The above example programs explicitly call the function TipcSrvCreate to create a connection to RTserver. RTclient can also automatically create a connection to RTserver if one is needed, such as when RTclient tries to publish a message to RTserver before it has created a connection to RTserver. Most of the TipcSrv* functions automatically attempt to create a connection to RTserver (by calling TipcSrvCreate themselves) if one is needed and the option Server_Auto_Connect is set to TRUE
.
The standard SmartSockets modules also use Server_Auto_Connect in a second way. During initialization, each of these standard processes uses Server_Auto_Connect to determine whether or not to require a connection to RTserver. If Server_Auto_Connect is TRUE
, the process requires a connection to RTserver, and creates one, if necessary, to start up. To run the standard processes without any connection to RTserver, Server_Auto_Connect must be set to FALSE
. Some standard data sources in the standard SmartSockets processes also require a connection to RTserver regardless of the value of Server_Auto_Connect.
Table 9 shows the TipcSrv* functions that do not automatically create a connection to RTserver
.
If a user-defined RTclient does not care when it creates a connection to RTserver, it never needs to call TipcSrvCreate and can just let the process automatically connect to RTserver when necessary. However, it is usually a good idea to explicitly connect to RTserver once all the necessary options have been set to the desired values.
When an unrecoverable error occurs on the connection to RTserver, the connection error callbacks for this connection are called (see Error Callbacks, for more details on connection error callbacks). The standard connection error callback function TipcCbSrvError normally takes care of reconnecting to RTserver. TipcCbSrvError uses the function TipcSrvCreate to reconnect to RTserver so that the same options are used to both connect and reconnect to RTserver. Any messages that were being buffered to be sent to RTserver are lost, but RTclient is able to continue. If the RTclient cannot reconnect to RTserver, it keeps a warm connection to RTserver in the hope that it is able to reconnect to RTserver in the near future. For more information on TipcCbSrvError and how it is automatically created as a connection error callback, see the man page for TipcCbSrvError in the TIBCO SmartSockets Application Programming Interface reference.
While most subject and monitoring information is kept in RTserver, RTclients do keep track of the subjects they are subscribing to and monitoring categories they are watching, so that when they reconnect to RTserver, they can easily start subscribing to those subjects and watching those monitoring categories again.
If several RTclients are connected to RTserver and they all have errors occur on their connections to RTserver (for example, RTserver fails or the node RTserver is running on fails), it is possible that all of the RTclients might try to restart RTserver. These many simultaneous restart attempts can use large amounts of network resources. Avoid this when you configure the option Server_Names through the use of the start prefixes (discussed in Start Prefix), by ensuring that only one or two of the RTclients ever tries to restart RTserver. The default behavior is for RTclients to not attempt to restart the RTserver.
If an RTclient is done communicating with RTserver, it can destroy its connection to RTserver. The connection can be fully destroyed, which destroys all RTserver-related information in an RTclient, or it can be partially destroyed, which leaves a subset of the full information in a warm connection. Warm connections are discussed in Warm Connection to RTserver. From this point on, the term destroying the connection to RTserver is used to mean fully destroying the connection to RTserver.
The function TipcSrvDestroy is used to destroy the connection to RTserver. For example:
if (!TipcSrvDestroy(T_IPC_SRV_CONN_NONE)) { TutOut("Could not destroy connection to RTserver: error <%s>.\n", TutErrStrGet()); }
The disconnect
command provides a way to use TipcSrvDestroy from the SmartSockets command interface (see the man page for disconnect
in Chapter 9, Command Reference, for more details). After a process destroys its connection to RTserver it can continue as if it had never been connected to RTserver.
For a full destroy, TipcSrvDestroy removes all local subject information, destroys all internal callbacks (for options like Server_Read_Timeout and Log_In_Data), destroys the connection, and finally calls the server destroy callbacks (see RTclient-Specific Callbacks on server destroy callbacks). All messages that have been sent to the connection to RTserver but not flushed are lost after a call to TipcSrvDestroy. If a warm connection is retained, all messages that have been read from the connection to RTserver but not processed after the call to TipcSrvDestroy(T_IPC_SRV_CONN_WARM) are still available.
TipcSrvDestroy also attempts to send a DISCONNECT message to notify RTserver of the value of the option Server_Disconnect_Mode. DISCONNECT messages are discussed in DISCONNECT Message Type.
An RTclient using the TCP protocol to connect to RTserver can lose outgoing messages if the process terminates without calling TipcSrvDestroy. TCP/IP’s SO_LINGER
option, which preserves data, is ignored when closing a socket that has non-blocking I/O enabled. While data loss is rare on UNIX, MVS, and OpenVMS, it can happen frequently on Windows. TipcSrvDestroy sets the block mode of the connection to FALSE
before closing the connection’s socket, forcing the operating system to deliver all flushed outgoing messages.
The function TipcSrvSubjectSetSubscribe can be used to start or stop subscribing to a subject. This code causes RTclient to start subscribing to the subject named /elec_pwr
:
if (!TipcSrvSubjectSetSubscribe("/elec_pwr", TRUE)) { TutOut("Could not start subscribing to the /elec_pwr subject.\n"); TutOut(" error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); }
Once RTclient starts subscribing to a subject, it receives all messages sent to RTserver that have that subject as their destination property. If the second parameter to TipcSrvSubjectSetSubscribe is FALSE
, then RTclient stops subscribing to the subject. TipcSrvSubjectSetSubscribe causes a SUBJECT_SET_SUBSCRIBE message to be sent to RTserver, but the message is not automatically flushed. See Sending Messages for a discussion of sending and buffering messages to RTserver.
The function TipcSrvSubjectGetSubscribe can be used to determine whether or not RTclient is subscribing to a subject. For example:
T_BOOL subscribe_status;
if (!TipcSrvSubjectGetSubscribe("/elec_pwr", &subscribe_status)) {
/* error */
}
TutOut("This process %s subscribing to the /elec_pwr subject.\n",
subscribe_status ? "is" : "is not");
The subscribe
and unsubscribe
commands provide a way to use TipcSrvSubjectSetSubscribe from the SmartSockets command interface. See subscribe and unsubscribe.
There are many types of information about subjects that can be monitored. For information on monitoring, see Chapter 5, Project Monitoring.
As described in Unique Subject, an RTclient has a unique subject, which RTserver requires to be unique among all processes in a project. This code shows how an RTclient can use this property to ensure that it is the only process subscribing to a subject:
TutCommandParseStr("setopt unique_subject my_subject"); if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL) && TutErrNumGet() == T_ERR_SRV_ACCESS_DENIED) { TutOut("Another RTclient is using my_subject!\n"); }
Because the unique subject must be unique among all processes in a project, it can be used to prevent multiple similarly-configured processes from running (whether accidentally or intentionally). Because the default value for the unique subject is generated from the node name and process identifier of the RTclient, the default value is usually adequate for RTclients that aren’t using guaranteed message delivery. Configuring GMD discusses how Unique_Subject must be explicitly set to use file-based GMD.
RTclient automatically subscribes to its unique subject when it connects to RTserver, and SmartSockets does not allow RTclient to ever stop subscribing to its unique subject.
The function TipcSrvStdSubjectSetSubscribe can be used to start or stop subscribing to the standard subjects. This code causes RTclient to start subscribing to all standard subjects, including the _time
subject:
If the first parameter to TipcSrvStdSubjectSetSubscribe is FALSE
, then RTclient stops subscribing to the standard subjects. If the second parameter to TipcSrvStdSubjectSetSubscribe is FALSE
, then the _time
subject is not included with the standard subjects.
Subject callbacks are functions that are executed while processing a message with the given destination (that is, subject). Subject callbacks are similar to connection process callbacks, but have added flexibility to filter the callbacks based on destination and message type. The functions TipcSrvSubjectCbCreate and TipcSrvSubjectDefaultCbCreate can be used to create subject callbacks. The following code causes RTclient to create a subject callback that gets executed when any type of message is received by the "/stocks" subject:
See RTclient-Specific Callbacks for more information on this subject callbacks.
Once RTclient has connected to RTserver, it can create callbacks to be executed when certain operations occur. Most of the connection callback types, except encode and decode callbacks, are available with the connection to RTserver. These connection callback types are discussed in detail in the section Callbacks. In addition to the connection callbacks, subject, server create, server destroy, and server names traverse callbacks are available for the connection to RTserver.
For the connection to RTserver, callbacks are manipulated with TipcSrv* functions instead of TipcConn* functions. The TipcSrv*CbCreate functions create callbacks in the connection to RTserver, and the TipcSrv*CbLookup functions look up existing callbacks.
This creates a process callback called whenever a NUMERIC_DATA message is processed:
mt = TipcMtLookupByNum(T_MT_NUMERIC_DATA); if (mt == NULL) { TutOut("Could not look up NUMERIC_DATA msg type: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } if (TipcSrvProcessCbCreate(mt, cb_process_numeric_data, NULL) == NULL) { TutOut("Could not create NUMERIC_DATA process cb: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); }
The callback functions themselves are written exactly the same for the connection to RTserver as for any other connection. The following code shows a callback function that prints the values in a NUMERIC_DATA message. The definition and prototype for every callback function must use the T_ENTRY macro for cross-platform compatibility.
/* =============================================================== */
/*..cb_process_numeric_data -- process callback for NUMERIC_DATA */
static void T_ENTRY cb_process_numeric_data( T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg) { T_STR name; T_REAL8 value; TutOut("Entering cb_process_numeric_data.\n");/* set current field to first field in message */
if (!TipcMsgSetCurrent(data->msg, 0)) { TutOut("Could not set current field of message: error <%s>.\n", TutErrStrGet()); return; }/* access and print fields */
while (TipcMsgNextStrReal8(data->msg, &name, &value)) { TutOut("%s = %s\n", name, TutRealToStr(value)); }/* make sure we reached the end of the message */
if (TutErrNumGet() != T_ERR_MSG_EOM) { TutOut("Did not reach end of message: error <%s>.\n", TutErrStrGet()); } }/* cb_process_numeric_data */
These callbacks can be created either before or after RTclient starts working with subjects, but the callbacks should be created before any messages are sent or received (if the callbacks are needed for those messages).
RTclient also has callbacks that can be called when certain RTclient-specific events occur, such as when the connection to RTserver is created. See RTclient-Specific Callbacks for more information on these callback types.
RTclient receives and processes messages from the connection to RTserver the same way that non-RTserver connections are used. See Receiving and Processing Messages, for more details. As with callbacks, the TipcSrv* functions are used, not the TipcConn* functions.
For example:
/* If an error occurs, then TipcSrvMainLoop will restart RTserver */
/* and return FALSE. We can safely continue. */
for (;;) { if (!TipcSrvMainLoop(T_TIMEOUT_FOREVER)) { TutOut("TipcSrvMainLoop failed: error <%s>.\n", TutErrStrGet()); } }
The above loop handles the case where RTclient loses its connection to RTserver and reconnects again, and simply prints some diagnostic output each time this occurs. Each program can add more or less error checking as desired.
When RTclient creates a connection to RTserver, the function TipcSrvCreate also creates a connection process callback for CONTROL messages using the standard callback function TipcCbSrvProcessControl. This callback function uses the value of the option Enable_Control_Msgs to check if the command is enabled, and if allowed, RTclient then calls TutCommandParseStr to have the process command interface execute the command. This automatic processing of CONTROL messages allows RTclient to publish remote commands to any other RTclient. See Enable_Control_Msgs for details on how to properly configure CONTROL message security.
For more information on TipcCbSrvProcessControl and how it is automatically created as a connection process callback, see the reference page for TipcCbSrvProcessControl in the TIBCO SmartSockets Application Programming Interface reference.
RTclient sends (publishes) messages using the connection to RTserver in a way that is similar, but not quite identical, to the way other connections are used. The functions TipcSrvMsgSend, TipcSrvMsgWrite, and TipcSrvMsgWriteVa differ from their TipcConn* relatives in these ways:
check_server_msg_send
parameter (of type T_BOOL) that determines whether or not the option Server_Msg_Send is checked before actually sending the message.destination
parameter (of type T_STR) that is the name of a subject to be used as the destination property of the message being sent (to use TipcSrvMsgSend the destination property of the message must be set first with TipcMsgSetDest).
The Server_Msg_Send option specifies whether or not RTclient should send messages to RTserver. If check_server_msg_send
is TRUE
and Server_Msg_Send is FALSE
, then the above TipcSrv* functions do not send the message. Some messages sent internally by the SmartSockets IPC library, such as SUBJECT_SET_SUBSCRIBE messages, are always sent regardless of the setting of Server_Msg_Send. This option is useful for backup processes that should receive messages from RTserver but not send any out. The use of any option greatly simplifies the development of such backup processes; for a complete example see Running an RTclient With a Hot Backup. You should normally use TRUE
for the check_server_msg_send
parameter to the above TipcSrv* functions if you wish to use the Server_Msg_Send option to easily create backup processes.
This uses TipcSrvMsgWrite to send an INFO message to all processes in a project:
TutOut("Publishing a CONTROL message to stop the receiver(s).\n"); mt = TipcMtLookupByNum(T_MT_CONTROL); if (mt == NULL) { TutOut("Could not look up CONTROL msg type: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } if (!TipcSrvMsgWrite("_ie", mt, TRUE, T_IPC_FT_STR, "quit force", NULL)) { TutOut("Could not publish CONTROL message: error <%s>.\n", TutErrStrGet()); }
The previous example could be rewritten as follows to use TipcSrvMsgSend instead of TipcSrvMsgWrite:
TutOut("Publishing a CONTROL message to stop the receiver(s).\n"); mt = TipcMtLookupByNum(T_MT_CONTROL); if (mt == NULL) { TutOut("Could not look up CONTROL msg type: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } msg = TipcMsgCreate(mt); if (msg == NULL) { TutOut("Could not create CONTROL message: error <%s>.\n", TutErrStrGet()); TutExit(T_EXIT_FAILURE); } if (!TipcMsgSetDest(msg, "_ie") || !TipcMsgAppendStr(msg, "quit force") || !TipcSrvMsgSend(msg, TRUE)) { TutOut("Could not construct and publish CONTROL message.\n"); TutOut(" error <%s>.\n", TutErrStrGet()); }
The connection to RTserver has the same auto flush size property that all other connections have for controlling how many bytes of outgoing data are buffered before being automatically flushed. This property can be set with the function TipcSrvSetAutoFlushSize, but it can also be accessed with the Server_Auto_Flush_Size option. This option can be set in startup command files for greater convenience in all RTclients.
TIBCO SmartSockets™ User’s Guide Software Release 6.8, July 2006 Copyright © TIBCO Software Inc. All rights reserved www.tibco.com |