Skip navigation.

Programming a Tuxedo ATMI Application Using C

  Previous Next vertical dots separating previous/next from contents/index/pdf Contents View as PDF   Get Adobe Reader

Writing Conversational Clients and Servers

This topic includes the following sections:

 


Overview of Conversational Communication

Conversational communication is the BEA Tuxedo system implementation of a human-like paradigm for exchanging messages between ATMI clients and servers. In this form of communication, a virtual connection is maintained between the client (initiator) and server (subordinate) and each side maintains information about the state of the conversation. The connection remains active until an event occurs to terminate it.

During conversational communication, a half-duplex connection is established between the client and server. A half-duplex connection allows messages to be sent in only one direction at any given time. Control of the connection can be passed back and forth between the initiator and the subordinate. The process that has control can send messages; the process that does not have control can only receive messages.

To understand how conversational communication works in a BEA Tuxedo ATMI application, consider the following example from an online banking application. In this example, a bank customer requests checking account statements for the past two months.

Figure 7-1 Example of Conversational Communication in an Online Banking Application

Example of Conversational Communication in an Online Banking Application


 
  1. The customer requests the checking account statements for the past two months.
  2. The Account Records Storage System responds by sending the first month's checking account statement followed by a More prompt for accessing the remaining month's statement.
  3. The customer requests the second month's account statement by selecting the More prompt.

Note: The Account Records Storage System must maintain state information so it knows which account statement to return when the customer selects the More prompt.

  1. The Account Records Storage System sends the remaining month's account statement.

As with request/response communication, the BEA Tuxedo system passes data using typed buffers. The buffer types must be recognized by the application. For more information on buffer types, refer to Overview of Typed Buffers.

Conversational clients and servers have the following characteristics:

Conversational communication differs from request/response communication in the following ways:

 


Joining an Application

A conversational client must join an application via a call to tpinit() before attempting to establish a connection to a service. For more information, refer to Writing Clients.

 


Establishing a Connection

The tpconnect(3c) function sets up a conversation:

Use the following signature to call the tpconnect() function.

int
tpconnect(char *name, char *data, long len, long flags)

The following table describes the arguments to the tpconnect() function.

Table 7-1 tpconnect( ) Function Arguments

Argument

Description

name

Character pointer to a conversational service name. If you do not specify name as a pointer to a conversational service, the call fails with a value of -1 and tperrno is set to the error code TPENOENT.

data

Pointer to a data buffer. When establishing the connection, you can send data simultaneously by setting the data argument to point to a buffer previously allocated by tpalloc(). The type and subtype of the buffer must be types recognized by the service being called. You can set the value of data to NULL to specify that no data is to be sent.

The conversational service being called receives the data and len pointers via the TPSVCINFO data structure passed to it by main() when the service is invoked. (A request/response service receives the data and len pointers in the same way.) For more information on the TPSVCINFO data structure, refer to Defining a Service.

len

Length of the data buffer. If the buffer is self-defining (for example, an FML buffer), you can set len to 0.

flag

Specifies the flag settings. For a complete list of valid flag settings, refer to tpconnect(3c) in the BEA Tuxedo ATMI C Function Reference.

The system notifies the called service through the flag members of the TPSVCINFO structure.

The BEA Tuxedo system returns a connection descriptor (cd) when a connection is established with tpconnect(). The cd is used to identify subsequent message transmissions with a particular conversation. A client or conversational service can participate in more than one conversation simultaneously. The maximum number of simultaneous conversations is 64.

In the event of a failure, the tpconnect() function returns a value of -1 and sets tperrno to the appropriate error condition. For a list of possible error codes, refer to tpconnect(3c) in the BEA Tuxedo ATMI C Function Reference.

The following example shows how to use the tpconnect() function.

Listing 7-1 Establishing a Conversational Connection

#include atmi.h
#define FAIL -1
int cd1; /* Connection Descriptor */
main()
{
if ((cd = tpconnect("AUDITC",NULL,0,TPSENDONLY)) == -1) {
error routine
}
}

 


Sending and Receiving Messages

Once the BEA Tuxedo system establishes a conversational connection, communication between the initiator and subordinate is accomplished using send and receive calls. The process with control of the connection can send messages using the tpsend(3c) function; the process without control can receive messages using the tprecv(3c) function.

Note: Initially, the originator (that is, the client) decides which process has control using the TPSENDONLY or TPRECVONLY flag value of the tpconnect() call. TPSENDONLY specifies that control is being retained by the originator; TPRECVONLY, that control is being passed to the called service.

Sending Messages

To send a message, use the tpsend(3c) function with the following signature:

int
tpsend(int cd, char *data, long len, long flags, long *revent)

The following table describes the arguments to the tpsend() function.

Table 7-2 tpsend( ) Function Arguments

Argument

Description

cd

Specifies the connection descriptor returned by the tpconnect() function identifying the connection over which the data is sent.

data

Pointer to a data buffer. When establishing the connection, you can send data simultaneously by setting the data argument to point to a buffer previously allocated by tpalloc(). The type and subtype of the buffer must be types recognized by the service being called. You can set the value of data to NULL to specify that no data is to be sent.

The conversational service being called receives the data and len pointers via the TPSVCINFO data structure passed to it by main() when the service is invoked. (A request/response server receives the data and len pointers in the same way.) For more information on the TPSVCINFO data structure, refer to Defining a Service.

len

Length of the data buffer. If the buffer is self-defining (for example, an FML buffer), you can set len to 0. If you do not specify a value for data, this argument is ignored.

revent

Pointer to event value set when an error is encountered (that is, when tperrno(5) is set to TPEEVENT). For a list of valid event values, refer to tpsend(3c) in the BEA Tuxedo ATMI C Function Reference.

flag

Specifies the flag settings. For a list of valid flag settings, refer to tpsend(3c) in the BEA Tuxedo ATMI C Function Reference.

In the event of a failure, the tpsend() function returns a value of -1 and sets tperrno(5) to the appropriate error condition. For a list of possible error codes, refer to tpsend(3c) in the BEA Tuxedo ATMI C Function Reference.

You are not required to pass control each time you issue the tpsend() function. In some applications, the process authorized to issue tpsend() calls can execute as many calls as required by the current task before turning over control to the other process. In other applications, however, the logic of the program may require the same process to maintain control of the connection throughout the life of the conversation.

The following example shows how to invoke the tpsend() function.

Listing 7-2 Sending Data in Conversational Mode

if (tpsend(cd,line,0,TPRECVONLY,revent) == -1) {
(void)userlog("%s: tpsend failed tperrno %d",
argv[0],tperrno);
(void)tpabort(0);
(void)tpterm();
exit(1);
}

Receiving Messages

To receive data sent over an open connection, use the tprecv(3c) function with the following signature:

int
tprecv(int cd, char **data, long *len, long flags, long *revent)

The following table describes the arguments to the tprecv() function.

Argument

Description

cd

Specifies the connection descriptor. If a subordinate program issues the call, the cd argument should be set to the value specified in the TPSVCINFO structure for the program. If the originator program issues the call, the cd argument should be set to the value returned by the tpconnect() function.

data

Pointer to a data buffer. The data argument must point to a buffer previously allocated by tpalloc(). The type and subtype of the buffer must be types recognized by the service being called. This value cannot be NULL; if it is, the call fails and tperrno(5) is set to TPEINVAL.

The conversational service being called receives the data and len pointers via the TPSVCINFO data structure passed to it by main() when the service is invoked. (A request/response service receives the data and len pointers in the same way.) For more information on the TPSVCINFO data structure, refer to Defining a Service.

len

Length of the data buffer. If the buffer is self-defining (for example, an FML buffer), you can set len to 0. This value cannot be NULL; if it is, the call fails and tperrno(5) is set to TPEINVAL.

revent

Pointer to event value set when an error is encountered (that is, when tperrno is set to TPEEVENT). Refer to tprecv(3c) in the BEA Tuxedo ATMI C Function Reference for a list of valid event values.

flag

Specifies the flag settings. Refer to tprecv(3c) in the BEA Tuxedo ATMI C Function Reference for a list of valid flags.

Upon success, the *data argument points to the data received and len contains the size of the buffer. If len is greater than the total size of the buffer before the call to tprecv(), the buffer size has changed and len indicates the new size. A value of 0 for the len argument indicates that no data was received.

The following example shows how to use the tprecv() function.

Listing 7-3 Receiving Data in Conversation

if (tprecv(cd,line,len,TPNOCHANGE,revent) != -1) {
(void)userlog("%s: tprecv failed tperrno %d revent %ld",
argv[0],tperrno,revent);
(void)tpabort(0);
(void)tpterm();
exit(1);
}

 


Ending a Conversation

A connection can be taken down gracefully and a conversation ended normally through:

Note: The tpreturn() function is described in detail in Writing Request/Response Clients and Servers.

The following sections describe two scenarios for gracefully terminating conversations that do not include global transactions in which the tpreturn() function is used.

The first example shows how to terminate a simple conversation between two components. The second example illustrates a more complex scenario, with a hierarchical set of conversations.

If you end a conversation with connections still open, the system returns an error. In this case, either tpcommit() or tpreturn() fails in a disorderly manner.

Example: Ending a Simple Conversation

The following diagram shows a simple conversation between A and B that terminates gracefully.

Figure 7-2 Simple Conversation Terminated Gracefully

Simple Conversation Terminated Gracefully


 

The program flow is as follows:

  1. A sets up the connection by calling tpconnect() with the TPSENDONLY flag set, indicating that process B is on the receiving end of the conversation.
  2. A turns control of the connection over to B by calling tpsend() with the TPRECVONLY flag set, resulting in the generation of a TPEV_SENDONLY event.
  3. The next call by B to tprecv() returns a value of -1, sets tperrno(5) to TPEEVENT, and returns TPEV_SENDONLY in the revent argument, indicating that control has passed to B.
  4. B calls tpreturn() with rval set to TPSUCCESS. This call generates a TPEV_SVCSUCC event for A and gracefully brings down the connection.
  5. A calls tprecv(), learns of the event, and recognizes that the conversation has been terminated. Data can be received on this call to tprecv() even if the event is set to TPEV_SVCFAIL.

Note: In this example, A can be either a client or a server, but B must be a server.

Example: Ending a Hierarchical Conversation

The following diagram shows a hierarchical conversation that terminates gracefully.

Figure 7-3 Connection Hierarchy

 Connection Hierarchy


 

In the preceding example, service B is a member of a conversation that has initiated a connection to a second service called C. In other words, there are two active connections: A-to-B and B-to-C. If B is in control of both connections, a call to tpreturn() has the following effect: the call fails, a TPEV_SVCERR event is posted on all open connections, and the connections are closed in a disorderly manner.

In order to terminate both connections normally, an application must execute the following sequence:

  1. B calls tpsend() with the TPRECVONLY flag set on the connection to C, transferring control of the B-to-C connection to C.
  2. C calls tpreturn() with rval set to TPSUCCESS, TPFAIL, or TPEXIT, as appropriate.
  3. B can then call tpreturn(), posting an event (either TPEV_SVCSUCC or TPEV_SVCFAIL) for A.

Note: It is legal for a conversational service to make request/response calls if it needs to do so to communicate with another service. Therefore, in the preceding example, the calls from B to C may be executed using tpcall() or tpacall() instead of tpconnect(). Conversational services are not permitted to make calls to tpforward().

Executing a Disorderly Disconnect

The only way in which a disorderly disconnect can be executed is through a call to the tpdiscon(3c) function (which is equivalent to "pulling the plug" on a connection). This function can be called only by the initiator of a conversation (that is, the client).

Note: This is not the preferred method for bringing down a conversation. To bring down an application gracefully, the subordinate (the server) should call the tpreturn() function.

Use the following signature to call the tpdiscon() function:

int
tpdiscon(int cd)

The cd argument specifies the connection descriptor returned by the tpconnect() function when the connection is established.

The tpdiscon() function generates a TPEV_DISCONIMM event for the service at the other end of the connection, rendering the cd invalid. If a transaction is in progress, the system aborts it and data may be lost.

If tpdiscon() is called from a service that was not the originator of the connection identified by cd, the function fails with an error code of TPEBADDESC.

For a list and descriptions of all event and error codes, refer to tpdiscon(3c) in the BEA Tuxedo ATMI C Function Reference.

 


Building Conversational Clients and Servers

Use the following commands to build conversational clients and servers:

For conversational and request/response services, you cannot:

 


Understanding Conversational Communication Events

The BEA Tuxedo system recognizes five events in conversational communication. All five events can be posted for tprecv(); three can be posted for tpsend().

The following table lists the events, the functions for which they are returned, and a detailed description of each.

Table 7-3 Conversational Communication Events

Event

Received By

Description

TPEV_SENDONLY

tprecv()

Control of the connection has been passed; this process can now call tpsend().

TPEV_DISCONIMM

tpsend(),
tprecv(), tpreturn()

The connection has been torn down and no further communication is possible. The tpdiscon() function posts this event in the originator of the connection, and sends it to all open connections when tpreturn() is called, as long as connections to subordinate services remain open. Connections are closed in a disorderly fashion. If a transaction exists, it is aborted.

TPEV_SVCERR

tpsend()

Received by the originator of the connection, usually indicating that the subordinate program issued a tpreturn() without having control of the connection.

tprecv()

Received by the originator of the connection, indicating that the subordinate program issued a tpreturn() with TPSUCCESS or TPFAIL and a valid data buffer, but an error occurred that prevented the call from completing.

TPEV_SVCFAIL

tpsend()

Received by the originator of the connection, indicating that the subordinate program issued a tpreturn() without having control of the connection, and tpreturn() was called with TPFAIL or TPEXIT and no data.

tprecv()

Received by the originator of the connection, indicating that the subordinate service finished unsuccessfully (tpreturn() was called with TPFAIL or TPEXIT).

TPEV_SVCSUCC

tprecv()

Received by the originator of the connection, indicating that the subordinate service finished successfully; that is, it called tpreturn() with TPSUCCESS.

 

Skip navigation bar  Back to Top Previous Next