|COGENT Version 2.3 Help|
The Socket/Client box (only available in the registered version of COGENT) is the client half of a TCP/IP interface for COGENT. (See Socket/Server for the server half of the TCP/IP interface.) The interface allows multiple models to be run simultaneously (but asynchronously) on the same or different machines, communicating with each other via TCP/IP, and it allows COGENT models to interact with networked resources (such as web servers, Telnet clients or Java applications).
Socket/Client boxes accept a special trigger, open(Host : Port), where Host is an atom specifying a hostname (eg 'cogent.psyc.bbk.ac.uk' or localhost) or an IP address (eg '127.0.0.1'), and Port is a positive integer specifying a port on which a suitable server is listening. When a Socket/Client receives such a message from another box within a COGENT model, the box connects to the specified server and port. Messages can then be sent/received by the Socket/Client to/from the server.
Other than special triggers, all messages sent to a Socket/Client box along a send arrow will be transmitted along all open connections from or to that box. Similarly, any messages incoming through open connections will be transmitted along all send arrows leading from the Socket/Client box.
A model containing one or more Socket boxes will continue running if any connections from or to a box in the model are still open, or if a server box is listening for connections. Sending a Socket/Client box a close message will close all open connections from or to that box.
It should be noted that unlike COGENT models in general, model runs using Socket boxes cannot be halted and restarted in a later OOS session. This is because ending the OOS session will close any open connections, so clients will not still be connected when the model is restarted. Initialisation is usually required.
Socket boxes support two data formats to transmit and receive data: raw mode sends and receives lists of ASCII values, corresponding to lines of textual output and input, whereas the default mode sends and receives prolog terms. Raw mode is useful to allow COGENT models to interact with arbitrary networked systems, such as web servers, or with Telnet clients for user interaction. The default mode, by contrast, simply sends and receives prolog terms, which is more appropriate for direct communication between COGENT models.
Raw mode: If the box is configured to use raw mode, messages corresponding to lines of output must be specified as raw(LineString) where LineString is a prolog string, or a list of ASCII values, for example raw("hello") or equivalently raw([104, 101, 108, 108, 111]). These strings are each formatted on the output stream with a following newline (ASCII 10).
Similarly, lines of input from connections, terminated with newlines, are converted to raw(LineString) format before being passed along send arrows to other boxes. The newline character is not included in the parsed string, and any carriage returns (ASCII 13) in the input are ignored.
Default mode: In the default mode, any prolog term sent to a Socket box (except special triggers) will be sent on along any open connections to the peers, which must also be in default mode to ensure success.
So far, we have assumed that all outgoing messages will be sent to all open connections, and incoming messages could come from any connection, without identification. But a single Socket/Client may be connected to any number of servers, and similarly a single server may be connected to any number of Socket/Client boxes. Obviously there may be cases when we wish to send different messages to different connections, and when we want to identify the source of an incoming message. Both require a method for identifying individual open connections uniquely.
The problem of unique reference can be addressed by creating a system of identifiers. We have chosen to implement this as the state of the box, by analogy with the state of a buffer. In the present case, the state of the box comprises a list of unique identifiers for each currently open connection. It is maintained by the system, so it is not possible to directly add or delete elements to or from the state. Each element has the form socket(Host, UniqueID) where Host gives the hostname and port number, or a numeric IP address, and UniqueID is an integer generated by the system. It is possible to use the standard match procedure to read elements from the state.
Sending messages to individual connections can be achieved by simply attaching this identifier to the message to be sent. For example, if Socket=socket('localhost':15000, 8), then we can send a raw-mode message to this connection alone by using the form raw(Socket, LineString). For default mode, we have introduced a special term message/2, which is used in an analogous way: message(Socket, PrologTerm).
Attaching Socket identifiers to incoming messages happens analogously. It is necessary to specify that the box should tag incoming messages using a special property Tag Messages. If this is checked, all incoming messages will be in the form raw(Socket, LineString) or message(Socket, PrologTerm) instead of the default forms.
A final refinement of this tagging mechanism allows the setting of aliases for socket identifiers. If a connection has an alias, it can be specified instead of a socket/2 term on outgoing messages, and it will be used instead of a socket/2 term on tagged incoming messages, and when matching against the contents of the state. Aliases can be set in a variety of ways: first, an alternative form of the open message has a second argument that specifies the alias to be used for the connection, for example open(localhost:15000, myalias). Secondly, for an already-existing connection, it can be given an alias using a special message alias(Socket, Alias). Finally, a remote peer can specify its own alias, using a special message call_me(Alias). Setting an alias for a connection overrides any previous aliases for that connection.
To hit a web server and collect its output, first of all your Socket/Client box must be configured for Raw I/O. Now, using a process, open a connection to the server (usually on port 80), then send it a HTTP GET request, followed by a blank line, like this:
SEND open('www.myhost.com' : 80) to MyClient SEND raw("GET / HTTP/1.0") to MyClient SEND raw("") to MyClient
If all is well, the web server will reply with a stream of output, corresponding in this case to its root document, in the form of raw(...) messages representing individual lines. The output lines can be collected in order, by using an unrefracted, triggered rule to add the messages to a FIFO buffer with Duplicates enabled. The lines can then be read, in order, and at your leisure, from the buffer. In this example, there is no need to explicitly close the connection, as it will be closed in due course by the server.
By the way, to make this example more useful, you can replace the first "/" in the GET command with the path to some other page on that server, eg "GET /path/to/mypage.html HTTP/1.0". Also, you will notice that a few lines at the beginning of the web server's output are headers, and these are separated from the usual HTML content by a blank line. But this is not the place to teach HTTP...
We would like to thank David Glasspool and John Fox for their generous support, which allowed Peter Yule (email@example.com) to develop this box.
|COGENT Version 2.3 Help|