Creating Your Own Message Types


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

Table 1 Valid Field Types Allowed in Message Data
Field Type
Meaning
binary
non-restrictive array of characters, such as an entire C data structure or the entire contents of a file.
char
1-byte integer
int2
2- byte integer
int2_array
array of int2
int4
4-byte integer
int4_array
array of int4
int8
8-byte integer
int8_array
array of int8
msg
a message
msg_array
array of msg
real4
4-byte real number
real4_array
array of real4
real8
8-byte real number
real8_array
array of real8
real16
16-byte real number
real16_array
array of real16
str
a C string (NULL-terminated array of characters)
str_array
array of str
xml
an XML string

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.

Sample Programs

This section contains two complete sample programs for creating, sending, reading, and processing a user-defined message type called XYZ_COORD_DATA.

Step 30

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:

Line 2
Defines the unique number that identifies the new message type. This number must be used consistently in all programs that use the user-defined message type.
Line 13
Creates the new message type. This call to TipcMtCreate must be included in all programs that refer to the new message type.
Line 14
Assigns the new message type to the DATA category if logging is turned on for the messages.
Line 15
Creates a message of type XYZ_COORD_DATA.
Lines 19-21
Build the data part of the new message type.

This program publishes a series of ten XYZ_COORD_DATA messages.

Step 31

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:

Line 2
Defines the unique number that identifies the new message type. This number must be used consistently in all programs that use the user-defined message type. In addition, this number must be greater than zero.
Line 32
Creates the new message type. This call to TipcMtCreate must be included in all programs that refer to the new message type.
Line 33
Assigns the new message type to the DATA category if logging is turned on for messages.
Line 34
Defines the process callback to be used for messages of type XYZ_COORD_DATA.
Lines 5-15
This function is invoked when a message of type XYZ_COORD_DATA needs to be processed. It prints out the three numbers in the data part of the message.

Step 32

Compile and link rcv_umsg.c

Compile and link rcv_umsg.c.

Step 33

Start the receiving user-message program

Start the receiving user-message program in one window of your display:

UNIX:
$ rcv_umsg.x  
OpenVMS:
$ run rcv_umsg  
Windows:
$ rcv_umsg 

Step 34

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:

UNIX:
$ snd_umsg.x 
OpenVMS:
$ run snd_umsg 
Windows
$ snd_umsg 

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.

Step 35

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