As described earlier, TIBCO SmartSockets comes with a large number of pre-defined standard message types, such as NUMERIC_DATA and INFO. These standard message types are described in detail in Standard Message Types in Chapter 2, Messages, of the TIBCO SmartSockets User’s Guide.
When there is no standard message type to satisfy a requirement of your application, you can easily create your own message type (called a user-defined message type). Once you create it, the user-defined message type is handled in the same manner as a standard message type. To create a user-defined message type, use the function TipcMtCreate. To assign it a message logging category, use TipcSrvLogAddMt. The next example creates a message type named XYZ_COORD_DATA that has fields (X, Y, and Z coordinates) that are each four-byte integers. It also assigns it to the DATA
category for message logging.
#define XYZ_COORD_DATA 1001/* This must be greater than zero */
mt = TipcMtCreate("xyz_coord_data", XYZ_COORD_DATA, "int4 int4 int4"); if (mt == NULL) {/* error */
} if (!TipcSrvLogAddMt(T_IPC_SRV_LOG_DATA, mt)) {/* error */
}
A message type is a template for a specific kind of message. Once the message type is created, any number of messages of that type can be created. The first argument to TipcMtCreate is the message type name, which should be an identifier (T_STR). The second argument is the message type number, which is a signed four-byte integer (T_INT4). Message type numbers less than one are reserved for TIBCO SmartSockets standard message types. The standard TIBCO SmartSockets message types use similar names and numbers. For example, the message type with name NUMERIC_DATA has a defined number T_MT_NUMERIC_DATA. The third argument to TipcMtCreate is the message type grammar. It is used to identify the layout of fields in messages that use this message type.
The message grammar consists of a list of field types. Each field type in the grammar corresponds to one field in the message. For example, the standard message type TIME has a grammar "real8"
, which defines the first and only field as being an eight-byte real number. Table 1 lists the primitive types that can appear as a field in the grammar of a standard or user-defined message type. Comments (delimited by /* */
or (* *)
) are also allowed in the grammar
Occasionally, message types use a repetitive group of fields. For example, the NUMERIC_DATA message type allows zero or more name-value pairs. Curly braces ({}
) can be used in the message type grammar to indicate such a group. The grammar for the NUMERIC_DATA message type is "{ id real8 }"
and the grammar for HISTORY_STRING_DATA is "real8 { id str }"
. Groups must be at the end of the message type grammar and only one group is allowed for each grammar.
This section contains two complete sample programs for creating, sending, reading, and processing a user-defined message type called XYZ_COORD_DATA.
Copy the snd_umsg.c and rcv_umsg.c programs
Copy snd_umsg.c
and rcv_umsg.c
into your working directory. Under Windows, copy the makefiles snduw32m.mak
and rcvuw32m.mak
into your working directory.
This program creates and sends messages of user-defined type XYZ_COORD_DATA:
/*
* snd_umsg.c - create and send a series of messages of user-defined
* type XYZ_COORD_DATA
*/
/* $RTHOME/examples/smrtsock/tutorial/lesson4/snd_umsg.c */
1 #include <rtworks/ipc.h> 2 #define XYZ_COORD_DATA 1001 3 int main(int argc, char **argv) { 4 T_OPTION option; 5 T_IPC_MSG msg; 6 T_IPC_MT mt; 7 T_INT4 i;/* Set the name of the project */
8 option = TutOptionLookup("project"); 9 TutOptionSetEnum(option, "smartsockets");/* Connect to RTserver */
10 if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { 11 TutOut("Could not connect to RTserver!\n"); 12 TutExit(T_EXIT_FAILURE); }/* Define a new message type */
13 mt = TipcMtCreate("xyz_coord_data", XYZ_COORD_DATA, "int4 int4 int4");/* Assign new type to the DATA category for message logging */
14 TipcSrvLogAddMt(T_IPC_SRV_LOG_DATA, mt);/* Create a message of type XYZ_COORD_DATA */
15 msg = TipcMsgCreate(mt);/* Set the destination subject of the message */
16 TipcMsgSetDest(msg, "/tutorial/lesson4"); 17 for (i = 0; i < 30; i = i + 3) {/* In order to re-use the message, reset the number of the
fields in the message to zero */
18 TipcMsgSetNumFields(msg, 0);/* Build the data part of the message with 3 integers */
19 TipcMsgAppendInt4(msg, i); 20 TipcMsgAppendInt4(msg, i + 1); 21 TipcMsgAppendInt4(msg, i + 2);/* Send the message */
22 TipcSrvMsgSend(msg, TRUE); 23 TipcSrvFlush(); }/* Destroy the message */
24 TipcMsgDestroy(msg);/* Disconnect from RTserver */
25 TipcSrvDestroy(T_IPC_SRV_CONN_NONE); }/* main */
Some things to notice about this program:
This program publishes a series of ten XYZ_COORD_DATA messages.
Compile and link snd_umsg.c
Compile and link snd_umsg.c
.
You now need a program to read and process the messages of the new XYZ_COORD_DATA type. This program also needs to create the message type. It also needs to define a process callback for the new message type. The contents of rcv_umsg.c
is:
/*
* rcv_umsg.c - print out contents of messages of user-defined type XYZ_COORD_DATA
*/
/* $RTHOME/examples/smrtsock/tutorial/lesson4/rcv_umsg.c */
1 #include <rtworks/ipc.h> 2 #define XYZ_COORD_DATA 1001 3 static void T_ENTRY ProcessXYZ(T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg); 4 static void T_ENTRY DefaultReceiveFunc(T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg); /* ========================================================== */ /*..ProcessXYZ - callback for processing XYZ_COORD_DATA messages */ 5 static void T_ENTRY ProcessXYZ ( T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg ) { 6 T_IPC_MSG msg = data->msg; 7 T_INT4 field_value; 8 TutOut("Received XYZ_COORD_DATA message\n"); /* Set current field to first field in message */ 9 TipcMsgSetCurrent(msg, 0); /* Traverse Message; print value from each field */ 10 TipcMsgNextInt4(msg, &field_value); 11 TutOut("Field 1 Value = %d\n", field_value); 12 TipcMsgNextInt4(msg, &field_value); 13 TutOut("Field 2 Value = %d\n", field_value); 14 TipcMsgNextInt4(msg, &field_value); 15 TutOut("Field 3 Value = %d\n", field_value); } /* ProcessXYZ */ /* ============================================================ */ /*..DefaultReceiveFunc - default callback */ 16 static void T_ENTRY DefaultReceiveFunc ( T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg ) { 17 T_IPC_MSG msg = data->msg; 18 T_IPC_MT mt; 19 T_STR name; /* print out the name of the type of the message */ 20 TipcMsgGetType(msg, &mt); 21 TipcMtGetName(mt, &name); 22 TutOut("Receive: unexpected message type name is <%s>\n", name); } /* DefaultReceiveFunc */ /* ============================================================ */ 23 int main(int argc, char **argv) { 24 T_OPTION option; 25 T_IPC_MT mt; 26 T_IPC_MSG msg; /* Set the project name */ 27 option = TutOptionLookup("project"); 28 TutOptionSetEnum(option, "smartsockets"); /* Connect to the RTserver */ 29 if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { 30 TutOut("Could not connect to RTserver!\n"); 31 TutExit(T_EXIT_FAILURE); } /* Define a new message type */ 32 mt = TipcMtCreate("xyz_coord_data", XYZ_COORD_DATA, "int4 int4 int4"); /* Assign new type to the DATA category for message logging */ 33 TipcSrvLogAddMt(T_IPC_SRV_LOG_DATA, mt); /* Setup callback to process new message type */ 34 TipcSrvProcessCbCreate(mt, ProcessXYZ, NULL);/* Setup default callback to process anything but XYZ_COORD_DATA messages */
35 TipcSrvDefaultCbCreate(DefaultReceiveFunc, NULL); /* Start subscribing to the "/tutorial/lesson4" subject */ 36 TipcSrvSubjectSetSubscribe("/tutorial/lesson4", TRUE); /* Read and process all incoming messages */ 37 TipcSrvMainLoop(T_TIMEOUT_FOREVER); /* Disconnect from RTserver */ 38 TipcSrvDestroy(T_IPC_SRV_CONN_NONE); } /* main */
Some things to notice about this program that creates, reads and processes messages of user-defined type XYZ_COORD_DATA:
Compile and link rcv_umsg.c
Compile and link rcv_umsg.c
.
Start the receiving user-message program
Start the receiving user-message program in one window of your display:
Start snd_umsg
In another window, to send a series of XYZ_COORD_DATA messages to the receiving user-message program, run the new sending user-message program:
You should see this output in the window where you ran the receiving user-message program:
Received XYZ_COORD_DATA message
Field 1 Value = 0
Field 2 Value = 1
Field 3 Value = 2
Received XYZ_COORD_DATA message
Field 1 Value = 3
Field 2 Value = 4
Field 3 Value = 5
Received XYZ_COORD_DATA message
Field 1 Value = 6
Field 2 Value = 7
Field 3 Value = 8
/* ... Output omitted here ... */
Received XYZ_COORD_DATA message
Field 1 Value = 27
Field 2 Value = 28
Field 3 Value = 29
When the sending user-message program has completed, notice that the receiving user-message program is still hanging because it is waiting for more messages.
Interrupt the receiving user-message program
Type Ctrl-c to interrupt the receiving user-message program.
TIBCO SmartSockets™ Tutorial Software Release 6.8, July 2006 Copyright © TIBCO Software Inc. All rights reserved www.tibco.com |