This section of the Communicator User's Guide will describe the processes and mechanisms involved in implementing communication between RETSINA-based Software Agents. However, it should be noted, that the Communicator library can be used by any processes desiring to interoperate over a TCP/IP network. This is whether or not the Agents are based on the RETSINA architecture, or even if they are Agents at all, and possibly just networked applications.
The basic flow of Client or Server Agents can be seen in the table below. The two rudimentary types of Agents are very similar and complimentary to one another. The basic difference (other than the order of operations) is that a Client Agent initiates an activity (request), while a Server Agent is the target or resource being petitioned for information.
Server Client Initializations and Preparations Initializations and Preparations Wait for Client Connection Connect to Server Wait to Receive Request Send Request Process Requst Wait for Server Response Send Response Process Response Loop and wait for next Request Loop to Send next Requst Cleanup when done Close Connection and
Cleanup when doneMore detail of the steps involved is discussed below. Some simple code examples are available, later in this Communicator User's Guide, to help show the actual coding of the process. Click here to see a graphic illustration of this process.
The Communicator library attempts to hide the complexity of Agent interactions from the Agent programmer. This is because the activities that happen "behind-the-scenes" to facilitate the interaction between Agents are more complicated than just sending a message. This section will peel back some of the layers of the Communicator to describe some of the processes involved.The steps below, will describe how the Communicator prepares itself to talk to other agents using a ServerSocket, and then advertises itself as an available agent on the network using the Agent Name Server (ANS). (You will notice that this "server behaviour" is performed by any Agent utilizing the Communicator; so in effect, all Communicator-based Agents are initialized with the capability to function as Servers.)
Various queues and process threads are started at this point to monitor and manage connections and messaging with other Agents. When an Agent wants to establish a link or "connection" with another Agent, the ANS lookup and connection request processes are preformed.
The Connection between two Agents is the conduit that their messaging and interactions utilize. Some of the different aspects of these Connections include their being designated as Exclusive, or Shared by multiple processes or threads in the body of the Agent.
To make an Agent active on the network, the software needs to initialize a TCP/IP port (or socket) that can receive data from the network. Then the Agent will tell the ANS the name of this Agent, the machine (or host) name that the agent is running on, and finally the socket number where the agent will be listening. Last, but not least, the Agent needs to get things ready to handle incoming requests.All of these steps are done for the Agent when it creates an instance of the Communicator Object in the Agent code. Below is a list of the steps with a little more detail about each step. Click here for a picture of the process.
Creating a Communicator Object
- Initialize class variables from Constructor parameters
- Create a ServerSocket to wait for incoming connections
A ServerSocket is a special type of TCP/IP socket construct in Java that will listen for an incoming connection request. Lets pretend the ServerSocket was assigned to port 2000. When a connection is received (from a client opening a "Socket" to the server) a brand new TCP/IP socket will be created. Lets pretend it is assigned a value of 2001. The location of this new, automatically created, socket (2001) is sent back to the originating client "Socket" request. All future conversations between this Server Agent, and the Client that initiated the call will be transmitted between the Client's socket and port 2001 on the server. The original ServerSocket (2000) goes back into a wait-for-connection mode, awaiting the next Client Agent request.- Register With ANS - Agent's Name, Agent's Host, Agent's Port/Socket
At this point, the Agent finds an Agent Name Server and registers its common name, the name of the host computer it is running on, and the ServerSocket port number that was created to answer Client Agent requests.- Initialize a connectionTable data structure of type ConnectionTable
A ConnectionTable keeps track of the (possibly) many connections/links that may be open between client and server Agents.- Initialize a sharedConnectionToServerTable data structure of type ConnectionTable
since each "Connection" between a Client and Server can be "expensive" (they take up space, processing time, and require a delay to initiate or dispose of) an Agent programmer can choose to let multiple connections between one Client Agent and a Server Agent share the same TCP/IP connection. The Communicator will keep the data packets in order and not mix them up.- Create a replyWithHash data structure of type Hashtable
This data structure helps redirect incoming messages that are in reply to a specific message transmission- Create a logFacilityHash data structure of type Hashtable
The Communicator can automatically call various user-defined status logging facilities that might store, print, track, or display operations status information as the Communicator functions.- Create an incomingQueue data structure of type GenericQueue
All messages arriving over the network are deposited into this queue to be handled. From here, messages are given to tasks that are awaiting their reply, placed in special user defined queues, or dropped in the inputMsgQueue for later processing.- Create an inputMsgQueue data structure of type InputMsgQueue
After messages arrive (as described above) they will often be placed in this queue until the Agent requests to get the next message from the network. That "next message" may have already arrived and would be sitting in this message queue.- Create a dispatchQueue data structure of type GenericQueue
When an Agent asks to send a message, the message is placed into this outgoing queue. A thread will then see the message waiting and send it on its way. By doing this, the Agent can continue processing other data, while the Communicator handles the actual sending process and any network delays.- Start threads
- AcceptConnections
this thread handles all new connections arriving via the ServerSocket created above. It also starts another thread that watches each connection for activity, and then places incoming messages in the inputMsgQueue.- RouteInputMsgs
this thread handles the distribution of incoming messages that appear in the inputMsgQueue and need to be given to waiting tasks, routed/reply-to message queues, or just placed in the standard inputMsgQueue.- DispatchOutputMsgs
this thread handles messages that arrive at the dispatchQueue that are to be sent to a remote Agent.- Start any Message Log Facilities
this process will initialize any user defined logging Facilities. As described before, these facilities could store, print, display, or do some other action with various logging and status messages that the Communicator generates.
Prerequisites for Finding another Agent
Everything should be ready once an Agent has created (and therefore initialized) an instance of the Communicator object. This process ensures that the processes, queues, and other data structures required to interact with other Agents are in place. This step also establishes a working connection with an Agent Name Server, which will be used to locate the target Agent on the network.Request that a Connection be established to the remote Agent
The Agent makes a call to the Communicator's "openConnection" method and passes it the name of an remote Agent to which it desires to communicate. For example:call comm.openConnection("some-agent-name");This function will return a "ConnectionDescriptor" to the calling Agent if it is successful, or the value of null if there was a failure to create the Connection for any reason. The ConnectionDescriptor data object can then be used:
- to query information about the status of the Connection to the other Agent
- to query information about the names at each end of the connection, the port being used locally, and even find the Connection object being used (if needed)
- to specify where message are to be sent
- to specify from where a message is expected to arrive
Steps followed in opening a Connection
A client Agent can request a Shared Connection be created to a server Agent, or it can request an Exclusive Connection. These different types will be discussed in more detail later, but basically, shared connections will be faster and more efficient in their use of system resources, because multiple connections between a client and a server will share the same connection. The overhead of setting up and tearing down individual network links between the two systems will only occur once. Exclusive Connections demand that a separate and private link be established between the client and the server. New network links (and associated delays) are required for each connection.The client's calls to openConnection() (or openExclusiveConnection) to creates a Connection object will maintain the communications path to a server Agent. This process will follow this progression of events:
- Look Up the target Server Agent's Name
a request is sent to the Agent Name Server (ANS), found earlier, in order to find the hostname and active listening port of the remote Agent. The process will return the remote Agent's information if successful, or cause the openConnection method to return a null value instead of a valid ConnectionDescriptor when it fails.- Open a socket on the local machine and connect
using this local communications port, an attempt is made to contact the hostname and listener socket of the server Agent. After they negotiate the connection, both sides know the address and socket number of each other, for use in any subsequent information transfers.- Creation of PrintWriters and BufferedReaders
these constructs are initiated to facilitate message transfers, and to better handle the details of the socket communications.- Build a unique Connection Identifier
this text string helps the Communicators at each end of an Agent interaction specifically identify the source of a message.- Add to ConnectionTable
this new, and functioning, Connection is added to the appropriate tables, maintained by the Communicator, that keep track of all active Connections that the local Agent has in operation.- Start Thread to Handle Incoming Connection Activity
now that everything is in place, this thread will monitor the socket for any incoming traffic, parse it, convert the message format from an external network format, to the Agent's preferred internal message format, and then place the message into the inputMsgQueue described earlier. (Another thread, the Communicator's RouteInputMsgs thread, will watch for new messages arriving in the inputMsgQueue; and then send them to their proper internal destination queue or to a task that was placed "on-hold" awaiting an incoming message or reply.)- Create a ConnectionDescriptor Object
the ConnectionDescriptor object is the local Agent's interface to the Connection and therefore the remote Agent. All interactions with the remote Agent will be made by manipulations with this object, its data, and its methods. The ConnectionDescriptor points to the Connection, and the Connection points to its ConnectionDescriptor.- Return ConnectionDescriptor or null
finally, the ConnectionDescriptor is returned to the Agent that requested a connection be created. If there were any failures in any of the steps leading up to this point, the openConnection function will return a value of null to indicate that a valid connection could not be established.Basic of working with the ConnectionDescriptor
The most common operations that an Agent will perform with a ConnectionDescriptor involve I/O with the remote Agent. The following UML format descriptions show the function name and the parameters sent to the method. Each item (parameter and function call) are followed by a colon and an indicator of the parameter type, or the return value of the method. The leading plus sign (+) indicates that the method is public rather than private (-) or protected (#).
UML Description ConnectionDescriptor.getServerName() ConnectionDescriptor.getClientName() ConnectionDescriptor.getLocalport() ConnectionDescriptor.ConnectionName() ConnectionDescriptor.isConnectionAliveAndWell() Communicator.getAgentName() Communicator.getAgentHost() Communicator.getAgentPort() Communicator.lookupConnection() Communicator.getInternalMsgInstance() Communicator.getExternalMsgInstance()
review of ConnectionDescriptor Types of Connections Shared Exclusive opening and closing Connections status of Connection unique connection identifier connection status other connection methods and attributes
simple messaging synchronous messaging asynchronous messaging Communicator's role in messaging
components of message that Agent programmer will be working with basic fields set and get methods performative "basicRequiredFields" "basicOptionalFields" AgentMsg Interface InternalMsg Interface ExternalMsg Interface your message derived Object InputMsgObject class ReplyWithObject class
standards overview standards organizations active research facilities/groups directions KQML FIPA CMU-KQML others
review of Internal and External formats diverse Agent interactions InternalMsg Interface convertToExternal() method ExternalMsg Interface convertToInternal() method locations where expected locations where provided automatically
1.Agent, Building Message 2.Internal Message Manipulation 3.Communicator gets message 4.Translate Internal to External Format 5.Communicator sends message 6.(ANS-links-to-target?) 7.Network transfer 8.Communicator recieves message 9.Translate External to Internal Format 10.Internal Message enqueued 11.Agent accepts and processes message contents
basic formatting difference from straight KQML types of functions described below
building new building reply from incoming message setting fields getting field values resetting message contents checking for valid format
CONTENT field setting getting toString comparing values ONTOLOGY LANGUAGE
sender receiver reply with in reply to
PEFORMATIVE and other related values
Review of Internal vs External Converting between Review of Format Standards Inter Agent translation Intra Agent translation (agent app mapped to communicator expectations)
code segment showing message manipulation brief descrip and pointer/links to example programs
blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
Previously edited content for cut/paste
(In the following sections, briefly describe the types of functions available by logical grouping and make links to the more detailed information in the reference section.) 5.3 Finding information about the current environment Communicator.getAgentName() Communicator.getAgentHost() Communicator.getAgentPort() Communicator.lookupConnection() Communicator.getInternalMsgInstance() Communicator.getExternalMsgInstance() ConnectionDescriptor.getServerName() ConnectionDescriptor.getClientName() ConnectionDescriptor.getLocalport() ConnectionDescriptor.ConnectionName() ConnectionDescriptor.isConnectionAliveAndWell() AgentMsg.getRequiredFields():String[] AgentMsg.getOptionalFields():String[] AgentMsg.getInternalFields():String[] AgentMsg.getFilteredFields():String[] AgentMsg.getPerformative():String[] AgentMsg.getField(fieldName:String):String AgentMsg.existsField(fieldName:String):boolean AgentMsg.existsNonNullField(fieldName:String):boolean AgentMsg.existsNonEmptyField(fieldName:String):boolean AgentMsg.getFieldNames():Enumeration AgentMsg.isValidMsg():boolean 5.4 Manipulating the current environment 5.5 Asynchronous I/O queueMsg() getInputMsg() showInputMsg() getNextInputMsg() showNextInputMsg() 5.6 Synchronous I/O sendMsg() sendMsgAndGetReply() waitOnGetInputMsg() waitOnShowInputMsg() waitOnGetNextInputMsg() waitOnShowNextInputMsg() 5.7 I/O Queue functions queueMsg() routeInputMsgs() 5.8 Connection maintenance and management openConnection() openExclsiveConnection() closeConnection() lookupCOnnection() refuseNewConnections() flushMsgsAndStop() unRegisterWithANS()