In this section you modify your examples from previous lessons to use the most common types of callbacks available in TIBCO SmartSockets.
To see a callback function in action, you define a message process callback function to operate on the incoming NUMERIC_DATA message. As discussed earlier, one of the most commonly used callback types is the process callback. Process callback functions are a common way in TIBCO SmartSockets to perform the main processing of a message. Subject callbacks are another common way of processing messages.
This section describes a callback function in detail. This callback function, which is called when a message of type NUMERIC_DATA, is processed with TipcSrvMsgProcess or with TipcSrvMainLoop, simply accesses and prints the fields of the message.
Copy the receive.c program
Copy the receive.c
program into your working directory. Under Windows, you also need the makefile recvw32m.mak
in your working directory. Use the command chmod 777 *
to allow write access to the sample programs you copy.
The contents of the file receive.c
are:
/* receive.c - print out contents of NUMERIC_DATA message via
callback */
/* $RTHOME/examples/smrtsock/tutorial/lesson4/receive.c */
1 #include <rtworks/ipc.h> 2 static void T_ENTRY ProcessNumData(T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg);/* =========================================================== */
/*..ProcessNumData - callback for processing NUMERIC_DATA
messages */
3 static void T_ENTRY ProcessNumData ( T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg ) { 4 T_IPC_MSG msg = data->msg; 5 T_STR var_name; 6 T_REAL8 var_value; 7 TutOut("Received NUMERIC_DATA message\n");/* Set current field to first field in message */
8 TipcMsgSetCurrent(msg, 0);/* Traverse Message; print each name-value pair out */
9 while (TipcMsgNextStrReal8(msg, &var_name, &var_value)) { 10 TutOut("Var Name = %s; Value = %s\n", var_name, TutRealToStr(var_value)); } }/* ProcessNumData */
/* ============================================================ */
11 int main(int argc, char **argv) { 12 T_OPTION option; 13 T_IPC_MT mt; 14 T_IPC_MSG msg;/* Set the project name */
15 option = TutOptionLookup("project"); 16 TutOptionSetEnum(option, "smartsockets");/* Connect to the RTserver */
17 if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { 18 TutOut("Could not connect to RTserver!\n"); 19 TutExit(T_EXIT_FAILURE); }/* Setup callback to catch NUMERIC_DATA messages */
20 mt = TipcMtLookupByNum(T_MT_NUMERIC_DATA); 21 TipcSrvProcessCbCreate(mt, ProcessNumData, NULL);/* Start subscribing to the "/tutorial/lesson4" subject */
22 TipcSrvSubjectSetSubscribe("/tutorial/lesson4", TRUE);/* Read and process a message */
23 msg = TipcSrvMsgNext(T_TIMEOUT_FOREVER); 24 TipcSrvMsgProcess(msg);/* Disconnect from RTserver */
25 TipcSrvDestroy(T_IPC_SRV_CONN_NONE); }/* main */
The last command, TipcSrvDestroy, not only disconnects from the RTserver, but also destroys the callback you created, so you don’t need to use TutCbDestroy.
The first thing to notice is that the processing of the message has been moved into the callback function, ProcessNumData, lines 3-10. In addition, the callback function prototype on line 2 and definition on line 3 are both declared with the macro T_ENTRY. This is to assure cross-platform portability. A call to the function is also added in line 24 in the main program to invoke the callback when it is time to process the message.
Compile and link the receiving program
Under Windows, copy the makefile recvw32m.mak
into your working directory. Compile and link receive
.c as you did in the previous lesson.
Start the RTserver
Start RTserver if it is not already running:
![]() |
On platforms that support both 32- and 64-bit, use the rtserver64 command to run the 64-bit RTserver.
|
Start the receiving program
Start the receiving program in one window of your display:
Copy the send.c program
In another window, copy the send.c
program into your working directory. Under Windows, you also need the makefile sendw32m.mak
in your working directory.
Compile and link the sending program
Compile and link the sending program as you did before.
Start the sending program
Run the sending program:
You should see this output in the window where you ran the receiving program:
Received NUMERIC_DATA message Var Name = X; Value = 10 Var Name = Y; Value = 20 Var Name = Z; Value = 30
In the previous section, the example was set up to invoke a callback when a message needs to be processed. What happens if you send a message that is not of type NUMERIC_DATA? Next you try it and find out.
Copy the send2.c program
Copy the send2.c
program into your working directory. Under Windows, copy the makefile snd2w32m.mak
into your working directory.
That program is the equivalent of modifying the send.c
program by adding this call to TipcSrvMsgWrite after connecting to RTserver and before creating the NUMERIC_DATA message:
TipcSrvMsgWrite("/tutorial/lesson4", TipcMtLookupByNum(T_MT_INFO), TRUE, T_IPC_FT_STR, "Hello World!", NULL);
This new code sends an INFO message to your receive program, followed by a NUMERIC_DATA message.
Note that in the next two steps, you run receive
with send2
instead of the usual pairing of receive
with send
or receive2
with send2
.
Start the receiving program
In one window, start the receiving program:
Compile and link the send2.c program
To send a message to the receiving program, compile and link the send2.c
program.
Start the second sending program
Run the second sending program in another window, which sends an INFO and a NUMERIC_DATA message:
You do not see any output in the window where you ran the receiving program because the INFO message was received before the NUMERIC_DATA message. Because there was no callback created to process a message of type INFO, the message was ignored. The second message was sent, but because the receiving program is set up to read and process only one message, the NUMERIC_DATA message was never received.
Copy the receive2.c program
Copy the receive2.c
program into your working directory. Under Windows, copy the makefile rcv2w32m.mak
into your working directory.
It contains the receive.c
program and has been modified so that it can read and process any number of messages. Copying this file is the equivalent of replacing lines 23 and 24 of receive.c
with these three pieces of code:
/* Read and process all incoming messages */
while ((msg = TipcSrvMsgNext(T_TIMEOUT_FOREVER)) != NULL) {
TipcSrvMsgProcess(msg);
TipcMsgDestroy(msg);
}
This code creates a while loop that continues to read and process messages until TipcSrvMsgNext returns NULL
. Note that each time through the loop destroys the message after processing it.
Now you should create a default process callback to process any non-NUMERIC_DATA messages by adding this code to the receiving program after the callback for NUMERIC_DATA messages has been created:
/* Setup default callback to process anything but NUMERIC_DATA
messages */
TipcSrvDefaultCbCreate(DefaultReceiveFunc, NULL);
To complete the program, the default process callback function DefaultReceiveFunc should be added. This function simply prints out the name and type of the message. The changes have been made in the receive2.c
program:
/* receive2.c - print out contents of NUMERIC_DATA messages via callback */
/* $RTHOME/examples/smrtsock/tutorial/lesson4/receive2.c */
#include <rtworks/ipc.h> static void T_ENTRY ProcessNumData (T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg); static void T_ENTRY DefaultReceiveFunc(T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg);/* ================================================================ */
/*..ProcessNumData - callback for processing NUMERIC_DATA messages */
static void T_ENTRY ProcessNumData ( T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg ) { T_IPC_MSG msg = data->msg; T_STR var_name; T_REAL8 var_value; TutOut("Received NUMERIC_DATA message\n");/* Set current field to first field in message */
TipcMsgSetCurrent(msg, 0);/* Traverse Message; print each name-value pair out */
while (TipcMsgNextStrReal8(msg, &var_name, &var_value)) { TutOut("Var Name = %s; Value = %s\n", var_name, TutRealToStr(var_value)); } }/* ProcessNumData */
/* ================================================================ */
/*..DefaultReceiveFunc - default callback */
static void T_ENTRY DefaultReceiveFunc ( T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg ) { T_IPC_MSG msg = data->msg; T_IPC_MT mt; T_STR name;/* Print out the name of the type of the message */
TipcMsgGetType(msg, &mt); TipcMtGetName(mt, &name); TutOut("Receive: unexpected message type name is <%s>\n", name); }/* DefaultReceiveFunc */
/* ================================================================ */
int main(int argc, char **argv) { T_OPTION option; T_IPC_MT mt; T_IPC_MSG msg;/* Set the project name */
option = TutOptionLookup("project"); TutOptionSetEnum(option, "smartsockets");/* Connect to RTserver */
if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { TutOut("Could not connect to RTserver!\n"); TutExit(T_EXIT_FAILURE); }/* Setup callback to catch NUMERIC_DATA messages */
mt = TipcMtLookupByNum(T_MT_NUMERIC_DATA); TipcSrvProcessCbCreate(mt, ProcessNumData, NULL);/* Setup default callback to process anything but NUMERIC_DATA
messages */
TipcSrvDefaultCbCreate(DefaultReceiveFunc, NULL);/* Start subscribing to the "/tutorial/lesson4" subject */
TipcSrvSubjectSetSubscribe("/tutorial/lesson4", TRUE);/* Read and Process all incoming messages */
while ((msg = TipcSrvMsgNext(T_TIMEOUT_FOREVER)) != NULL) { TipcSrvMsgProcess(msg); TipcMsgDestroy(msg); }/* Disconnect from RTserver */
TipcSrvDestroy(T_IPC_SRV_CONN_NONE); }/* main */
Before compiling your updated receive2.c
program, copy the send3.c
program, which is the send2.c
program that was modified to send multiple messages.
Copy the send3.c program
Copy the send3.c
program into your working directory. Under Windows, copy the makefile snd3w32m.mak
into your working directory.
The contents of the send3.c
file are:
/* send3.c - send a INFO and then a series of NUMERIC_DATA
messages */
/* $RTHOME/examples/smrtsock/tutorial/lesson4/send3.c */
1 #include <rtworks/ipc.h> 2 int main(int argc, char **argv) { 3 T_OPTION option; 4 T_IPC_MSG msg; 5 T_INT4 i;/* Set the name of the project */
6 option = TutOptionLookup("project"); 7 TutOptionSetEnum(option, "smartsockets");/* Connect to RTserver */
8 if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { 9 TutOut("Could not connect to RTserver!\n"); 10 TutExit(T_EXIT_FAILURE); }/* Send an INFO message */
11 TipcSrvMsgWrite("/tutorial/lesson4", TipcMtLookupByNum(T_MT_INFO),TRUE, T_IPC_FT_STR, "Hello World!", NULL);/* Create a message of type NUMERIC_DATA */
12 msg = TipcMsgCreate(TipcMtLookupByNum(T_MT_NUMERIC_DATA));/* Set the destination subject of the message */
13 TipcMsgSetDest(msg, "/tutorial/lesson4");
/* Each time through the loop send a NUMERIC_DATA message with
3 values */
14 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 */
15 TipcMsgSetNumFields(msg, 0);/* Build the message with 3 variable-value pairs */
16 TipcMsgAppendStrReal8(msg, "X", (T_REAL8)i); 17 TipcMsgAppendStrReal8(msg, "Y", (T_REAL8)i + 1); 18 TipcMsgAppendStrReal8(msg, "Z", (T_REAL8)i + 2);/* Send the message */
19 TipcSrvMsgSend(msg, TRUE); 20 TipcSrvFlush(); }/* Destroy the message */
21 TipcMsgDestroy(msg);/* Disconnect from RTserver */
22 TipcSrvDestroy(T_IPC_SRV_CONN_NONE); }/* main */
Some things to learn from your new send3 program are:
In the next three steps, you run receive2
with send3
instead of the usual pairing of receive2
with send2
or receive3
with send3
.
Compile and link the receive2.c program
Compile and link the receive2.c
program.
Start the second receiving program
Start the second receiving program in one window of your display:
Compile and link the new send3.c program
In another window, to send a message to the second receiving program, compile and link the new send3.c
program.
Start the new sending program
To send a message to the receiving program, run the new sending program:
You should see this output in the window where you ran the receiving program:
Receive: unexpected message type name is <info>
Received NUMERIC_DATA message
Var Name = X; Value = 0
Var Name = Y; Value = 1
Var Name = Z; Value = 2
Received NUMERIC_DATA message
Var Name = X; Value = 3
Var Name = Y; Value = 4
Var Name = Z; Value = 5
/* ... Output omitted here ... */
Received NUMERIC_DATA message
Var Name = X; Value = 27
Var Name = Y; Value = 28
Var Name = Z; Value = 29
When the sending program has completed, notice that the receiving program is still hanging because it is waiting for more messages.
Interrupt the receiving program
Type Ctrl-c to interrupt the receiving program.
For each NUMERIC_DATA message received, the callback function ProcessNumData was invoked to print out the contents of the data part of the message. The very first message received was an INFO message. Because there were no process callbacks available for INFO messages, the default process callback, DefaultReceiveFunc, was called, which printed out the type of unexpected message received.
A while loop is added in receive2.c
to read and process all incoming messages:
while ((msg = TipcSrvMsgNext(T_TIMEOUT_FOREVER)) != NULL) { TipcSrvMsgProcess(msg); TipcMsgDestroy(msg); }
This entire loop can be replaced by a single call:
The TipcSrvMainLoop convenience function receives and processes messages from RTserver by calling TipcSrvMsgNext, TipcSrvMsgProcess, and TipcMsgDestroy over and over. TipcSrvMainLoop is a convenience function that keeps calling TipcSrvMsgNext with the time remaining from timeout
until TipcSrvMsgNext returns FALSE
. For each message that TipcSrvMainLoop gets, it processes the message with TipcSrvMsgProcess and then destroys the message with TipcMsgDestroy. Use 0.0 for timeout
to poll the RTserver connection and catch up on all pending messages that have accumulated. Use T_TIMEOUT_FOREVER for timeout
to read and process messages indefinitely. As soon as TipcSrvMsgNext returns FALSE
, TipcSrvMainLoop returns. See TipcSrvMainLoop in the TIBCO SmartSockets Application Programming Interface reference for more details.
A modified receive2.c
program, which uses TipcSrvMainLoop, is located in the file receive3.c
. You can compile, link, and run it with the sending program if you want to verify that it produces the same output as before.
Rather than processing a message based on its type, you can process a message based on its destination using subject callbacks. With a subject callback, you can specify a separate function for each subject (or group) of subjects you wish to operate on. When a message arrives at the receiver for the specified subject and is ready to be processed, the callback will be executed. Subject callbacks operate in a manner very similar to process callbacks except the function executed is selected based on the message’s destination, not its type. Just as with process callbacks, one can define a default subject callback to be executed if no callback has been defined for a given subject. (See TipcSrvSubjectDefaultCbCreate in the TIBCO SmartSockets Application Programming Interface for more details.)
To create a subject callback, make a call to TipcSrvSubjectCbCreate like this:
where subject
is the callback destination and mt is the message type the callback should be applied to. You can specify a value of NULL
for subject
or mt
to specify all. Subject callbacks are actually a superset of process callbacks as they allow message type and subject callbacks to be mixed; for example, execute this callback when a message of type T arrives on subject S.
Some examples of creating subject callbacks are:
mt = TipcMtLookupByNum(T_MT_INFO); /* Execute the function subj_cb for any message type which has a destination of "/tutorial" */ TipcSrvSubjectCbCreate("/tutorial", NULL, subj_cb, NULL); /* Execute the function subj_cb for any messages of type INFO, regardless of the destination */ TipcSrvSubjectCbCreate(NULL, mt, subj_cb, NULL); /* Execute the function subj_cb for any messages of type INFO, which have a destination of "/tutorial"*/ TipcSrvSubjectCbCreate("/tutorial", mt, subj_cb, NULL);
In this section you modify the examples used for process callbacks to show how easy it is to use subject callbacks. The following code describes a specific subject callback in detail. This callback function is called when a message is processed which has a destination of /tutorial/lesson4
. The callback function, ProcessLesson4, simply gets the type of the messages and then prints the fields of the message.
Copy the subject callback program
Copy the subject callback program, subjcbs.c
, into your working directory. Under Windows, you also need the makefile subjw32m.mak
in your working directory. The contents of the file subjcbs.c
are:
/* subjcbs.c - print out contents of messages processed via
subject callback */
/* $RTHOME/examples/smrtsock/tutorial/lesson4/subjcbs.c */
1 #include <rtworks/ipc.h> 2 static void T_ENTRY ProcessLesson4(T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg);/*============================================================= */
/*..ProcessLesson4 - callback for processing messages published to
the /tutorial/lesson4 subject */
3 static void T_ENTRY ProcessLesson4 ( T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg ) { 4 T_IPC_MSG msg = data->msg; 5 T_STR mt_name; 6 T_IPC_MT mt; 7 T_INT4 mt_num; 8 T_STR msg_text; 9 T_STR var_name; 10 T_REAL8 var_value;/* Get the message type and print it out */
11 TipcMsgGetType(msg, &mt); 12 TipcMtGetName(mt, &mt_name); 13 TutOut("*** Received message of type <%s>.\n", mt_name); 14 TipcMtGetNum(mt, &mt_num); 15 switch(mt_num) { 16 case T_MT_INFO: 17 TipcMsgSetCurrent(msg, 0); 18 TipcMsgNextStr(msg, &msg_text); 19 TutOut("Text from message = %s\n", msg_text); 20 break; 21 case T_MT_NUMERIC_DATA: 22 TipcMsgSetCurrent(msg, 0); 23 while (TipcMsgNextStrReal8(msg, &var_name, &var_value)) { 24 TutOut("Var Name = %s; Value = %s\n", var_name, TutRealToStr(var_value)); }/* while *
/ 25 break; 26 default: 27 TutOut("Unable to process messages of this type!\n"); 28 break; }/* switch */
}/* ProcessLesson4 */
/* ====================================================== */
29 int main(int argc, char **argv) { 30 T_OPTION option;/* Set the project name */
31 option = TutOptionLookup("project"); 32 TutOptionSetEnum(option, "smartsockets");/* Connect to the RTserver */
33 if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { 34 TutOut("Could not connect to RTserver!\n"); 35 TutExit(T_EXIT_FAILURE); }/* if */
/* Setup callback to catch all messages sent to
the "/tutorial/lesson4 subject" */
36 TipcSrvSubjectCbCreate("/tutorial/lesson4", NULL, ProcessLesson4, NULL);/* Start subscribing to the "/tutorial/lesson4" subject */
37 TipcSrvSubjectSetSubscribe("/tutorial/lesson4", TRUE);/* Read and process all incoming messages */
38 TipcSrvMainLoop(T_TIMEOUT_FOREVER);/* Disconnect from RTserver */
39 TipcSrvDestroy(T_IPC_SRV_CONN_NONE); }/* main */
Some interesting things to learn from your new subjcbs
program are:
You will now execute the new program using subject callbacks to verify that it works correctly.
Compile and link
Compile and link the program.
Start the subject callback program
Start the subject callback program in one window of your display:
Start the sending program
Run the sending program from the previous example:
The sending program sends an INFO message followed by a series of NUMERIC_DATA messages. You should see this output in the window where you ran the subject callback program:
Received message of type <info>.
Text from message = Hello World!
Rec*** Received message of type <info>.
Text from message = Hello World!
*** Received message of type <numeric_data>.
Var Name = X; Value = 0
Var Name = Y; Value = 1
Var Name = Z; Value = 2
*** Received message of type <numeric_data>.
Var Name = X; Value = 3
Var Name = Y; Value = 4
Var Name = Z; Value = 5
/* ... Output omitted here ... */
*** Received message of type <numeric_data>.
Var Name = X; Value = 27
Var Name = Y; Value = 28
Var Name = Z; Value = 29
When send3
has completed, notice that subjcbs
is still hanging; it is waiting for more messages.
Interrupt the subject callback program
Type Ctrl-c to interrupt the subject callback program.
For each message received, the callback function ProcessLesson4 was invoked to print out the contents of the data part of the message, regardless of the type of the message.
The example in the previous section can be further modified to specify a different subject callback for each of the different message types: INFO and NUMERIC_DATA. This is done by specifying two new callback functions: ProcessInfo and ProcessNumData. In the main program, two calls are required to TipcSrvSubjectCbCreate, one for each of the message types. The complete example is:
#include <rtworks/ipc.h> static void T_ENTRY ProcessInfo(T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg); static void T_ENTRY ProcessNumData(T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg);/* ================================================================ */
/*..ProcessInfo - callback for processing INFO messages published
to the /tutorial/lesson4 subject */
static void T_ENTRY ProcessInfo ( T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg ) { T_IPC_MSG msg = data->msg; T_STR msg_text; TutOut("*** Received INFO message\n"); TipcMsgSetCurrent(msg, 0); TipcMsgNextStr(msg, &msg_text); TutOut("Text from message = %s\n", msg_text); }/* ProcessInfo */
/* ================================================================ */
/*..ProcessNumData - callback for processing NUMERIC_DATA messages
published to the /tutorial/lesson4 subject */
static void T_ENTRY ProcessNumData ( T_IPC_CONN conn, T_IPC_CONN_PROCESS_CB_DATA data, T_CB_ARG arg ) { T_IPC_MSG msg = data->msg; T_STR var_name; T_REAL8 var_value; TutOut("*** Received NUMERIC_DATA message\n"); TipcMsgSetCurrent(msg, 0); while (TipcMsgNextStrReal8(msg, &var_name, &var_value)) { TutOut("Var Name = %s; Value = %s\n", var_name, TutRealToStr(var_value)); }/* while */
}/* ProcessNumData */
/* =============================================================== */ int main(int argc, char **argv) { T_OPTION option; T_IPC_MT mt;/* Set the project name */
option = TutOptionLookup("project"); TutOptionSetEnum(option, "smartsockets");/* Connect to the RTserver */
if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { TutOut("Could not connect to RTserver!\n"); TutExit(T_EXIT_FAILURE); }/* if */
/* Setup callback to catch INFO messages sent to
/tutorial/lesson4 subject */
TipcSrvSubjectCbCreate("/tutorial/lesson4", TipcMtLookupByNum(T_MT_INFO), ProcessInfo, NULL);/* Setup callback to catch NUMERIC_DATA messages sent to
/tutorial/lesson4 subject */
TipcSrvSubjectCbCreate("/tutorial/lesson4", TipcMtLookupByNum(T_MT_NUMERIC_DATA), ProcessNumData, NULL);/* Start subscribing to the "/tutorial/lesson4" subject */
TipcSrvSubjectSetSubscribe("/tutorial/lesson4", TRUE);/* Read and process all incoming messages */
TipcSrvMainLoop(T_TIMEOUT_FOREVER);/* Disconnect from RTserver */
TipcSrvDestroy(T_IPC_SRV_CONN_NONE); }/* main */
For more details on mixing subject and message type callbacks, see the TIBCO SmartSockets User’s Guide.
Earlier in this lesson, you saw example programs that used process and subject callbacks to work with messages. In this section two new callback types are shown: server create and server destroy. Server create callbacks are executed when an RTclient connects to an RTserver and server destroy callbacks are executed when an RTclient disconnects from an RTserver.
In this section, you execute these callbacks using a simple example. The program, srvcbs, prompts you for a password each time it tries to connect to RTserver. If the password is incorrect, the program is disconnected from RTserver and terminated.
Copy the create callback program
Copy the create callback program, srvcbs.c
, into your working directory. Under Windows, copy the makefile svcbw32m.mak
into your working directory.
The contents of srvcbs.c
are:
/* srvcbs.c - shows example uses of server create/destroy callbacks */
/* $RTHOME/examples/smrtsock/tutorial/lesson4/srvcbs.c */
#include <rtworks/ipc.h> #define MAX_PASSWD_LENGTH 20 static void T_ENTRY server_connect(T_IPC_CONN conn, T_IPC_SRV_CREATE_CB_DATA data, T_CB_ARG arg); static void T_ENTRY server_disconnect(T_IPC_CONN conn, T_IPC_SRV_CREATE_CB_DATA data, T_CB_ARG arg);/* ================================================================ */
/*..server_connect - ask for password when connecting to RTserver */
static void T_ENTRY server_connect ( T_IPC_CONN conn, T_IPC_SRV_CREATE_CB_DATA data, T_CB_ARG arg ) { T_STR password_correct = "smartsockets\n"; T_CHAR password_entered[MAX_PASSWD_LENGTH];/* Prompt for password when trying to connect to RTserver */
TutOut("Connecting to RTserver...\n"); TutOut("Please enter password : "); fgets(password_entered, MAX_PASSWD_LENGTH, stdin);/* If password is correct, let them connect to RTserver,
otherwise disconnect from RTserver and exit program */
if (!strcmp(password_entered, password_correct)) {/* Passwords matched */
TutOut("Password accepted!\n"); } else {/* Password did not match */
TutOut("Password is not correct!\n"); TutOut("You are being disconnected from RTserver\n"); TipcSrvDestroy(T_IPC_SRV_CONN_NONE); TutExit(T_EXIT_FAILURE); }/* if */
}/* server_connect */
/* ================================================================ */
/*..server_disconnect - callback for server destroy events */
static void T_ENTRY server_disconnect ( T_IPC_CONN conn, T_IPC_SRV_CREATE_CB_DATA data, T_CB_ARG arg ) { TutOut("...Disconnecting from RTserver\n"); }/* server_disconnect */
/* ================================================================ */
int main(int argc, char **argv) {/* Setup server create callback */
TipcSrvCreateCbCreate(server_connect, NULL);/* Setup server destroy callback */
TipcSrvDestroyCbCreate(server_disconnect, NULL);/* Connect to RTserver */
if (!TipcSrvCreate(T_IPC_SRV_CONN_FULL)) { TutOut("Could not connect to RTserver!\n"); TutExit(T_EXIT_FAILURE); }/* Read and process all incoming messages */
while (1) { TipcSrvMainLoop(T_TIMEOUT_FOREVER); }/* Disconnect from RTserver*/
TipcSrvDestroy(T_IPC_SRV_CONN_NONE); }/* main */
Some things to learn from your new server callback program are:
server_connect
) is defined in the call to TipcSrvCreateCbCreate.server_disconnect
) is defined in the call to TipcSrvDestroyCbCreate.Compile and link the server create program
Compile and link the server create program.
Start the server create program
Start the server create program in one window of your display:
The program produces output similar to this:
Connecting to project <rtworks> on <_node> RTserver. Using local protocol. Message from RTserver: Connection established. Start subscribing to subject </_workstation.tibco.com_19365>. Connecting to RTserver... Please enter password:
Note that the last two lines of output came from the server create callback. This was executed when the process tried to connect to RTserver for the first time. At this point you are being prompted for a password.
Enter the password
Enter smartsockets
as the password and press the return key:
The program produces the text Password accepted!
. The program is now successfully connected to RTserver. Let’s manually break the connection to RTserver and see what happens.
Stop the RTserver
In another window, stop the RTserver process using a command line argument to the rtserver
command:
The program produces this new output in the window where you ran srvcbs
:
WARNING: Lost connection to RTserver: error code = 10. ...Disconnecting from RTserver Attempting to reconnect to RTserver. Connecting to project <rtworks> on <_node> RTserver. Using local protocol. Could not connect to <_node> RTserver. Connecting to project <rtworks> on <_node> RTserver. Using tcp protocol. Could not connect to <_node> RTserver. Attempting auto-start of RTserver. . . . Connecting to project <rtworks> on <_node> RTserver. Using local protocol. Message from RTserver: Connection established. Start subscribing to subject </_workstation.tibco.com_19375> again. Connecting to RTserver... Please enter password:
Stopping the RTserver resulted in a sequence of events happening:
srvcbs
then restarted RTserver and tried to reconnect to it. This is a fault tolerant feature of TIBCO SmartSockets and is covered in more detail in Lesson 6: Fault Tolerance.Enter an incorrect password
This time, enter an incorrect password:
You should see output similar to this:
In this case, the server create callback disconnected from RTserver and terminated the program. In disconnecting from RTserver, the server destroy callback was executed again. This shows that callbacks can cause other callbacks to be executed.
In addition to being used for process authentication as shown in the srvcbs program, server create callbacks are useful for creating other callbacks (such as server process callbacks) that cannot be created until RTclient is connected to RTserver. See TipcSrvCreateCbCreate in the TIBCO SmartSockets Application Programming Interface for more details.
TIBCO SmartSockets™ Tutorial Software Release 6.8, July 2006 Copyright © TIBCO Software Inc. All rights reserved www.tibco.com |