[[Property:title|An overview of EiffelNet Mechanisms]]
[[Property:weight|2]]
[[Property:uuid|08d7ca19-65e3-7f35-fbce-a50d0aedf626]]
{{UpdateNeeded}}
To enable clients and servers to exchange objects, you will have to ensure that they can refer to a common '''address'''. At the predefined level this is really the only notion that you need to know, although it is useful to get the bigger picture, in particular the concept of '''socket '''(which enables systems to set up communication channels), the various forms of communication (single-machine versus multi-machine, stream versus datagram), the kinds of object structure that may be exchanged, the notion of packet, and how to associate commands with communication events. The following paragraphs review these ideas and the corresponding EiffelNet abstractions.
===Establishing a common address===
When two systems need to communicate through sockets, they must establish a binding through some common point of reference, called an '''address'''. Predictably, the notion of address is one of the important internal abstractions of EiffelNet, although in most cases developers of applications using EiffelNet do not need to manipulate address objects directly.
EiffelNet supports two modes of communication: single-machine and multi-machine. In the single-machine case, the two communicating systems are known to be running on the same machine. In the multi-machine case, also known as the '''network''' case, they may be running on different machines, and communication occurs through a network. These two modes clearly require a different binding mechanism.
When a client and a server reside on the same machine, they both have access to that machine's file system. This provides a straightforward binding mechanism: the common address will simply be a "path name", the Unix terminology for the full name of a file in a hierarchically organized file system. In the examples below this file will be ''/tmp/here ''(file ''here'' in the ''/tmp'' directory, conventionally used for temporary files). This file must not exist prior to the communication; it will be created by the socket mechanisms and then removed.
For the network style of communication, this simple device of using a path name is no longer applicable. To define a common address, we may use two elements of information: the name of a machine, and the indication of a '''port''' on that machine. More precisely:
* The port will be identified by an integer. In the examples below port ''2000'' will be used.
* The machine may be identified in either of two ways: its '''host name''' (the name assigned to the machine when the operating system was first installed on it) or its '''Internet address''', a sequence of numbers separated by periods, such as ''127.0.0.1''. EiffelNet routines that need an argument identifying a machine will indifferently take a host name or an Internet address, passed in either case as a string. In the examples below the identification will be a host name, given as the string ''"serverhost"''.
In network-style client-server communication, the mechanism will be dissymmetric, reflecting the possibility (noted earlier) of a single server catering to many clients. The clients will state both the machine identification of their intended server and the port on which they will talk to that server. The server, however, will only specify the port; this means that it makes itself available to any client that cares to talk to it on that port. This provides some of the essential flexibility of client-server communication, where only one of the partners needs to state beforehand whom it wants to talk to.
===Sockets and communication modes===
A software system will exchange objects with another by sending them to a socket. Although if you stay at the predefined level you will not need to manipulate sockets explicitly, it is useful to understand this concept and know about the corresponding EiffelNet classes.
You may think of a socket as a communication port; by attaching sockets together you enable communication between the corresponding systems, for example a client and a server:
[[Image:fig-2]]
EiffelNet has been designed so that sockets look very much like files. You send objects to a socket in the same way that you write objects onto a file, and receive objects from a socket in the same way that you read objects from a file. This fundamental commonality is reflected in the inheritance hierarchy of the corresponding classes:
[[Image:fig-3]]
Note that the hierarchy as shown is not complete; in particular the full structure uses classes STREAM (of which the STREAM_
classes are heirs) and DATAGRAM
for multiple inheritance ''. ''Only the classes below the dotted line are part of EiffelNet; the others are part of EiffelBase, the fundamental data structure and algorithm library of ISE Eiffel [ [[Bibliography|2]] ].
The most important property of this inheritance hierarchy is that it shows how sockets fit within the overall structure. Thanks to the common ancestor IO_MEDIUM
, socket classes have most of their features in common with files.
In normal usage, the only socket classes that you will need are four classes appearing at the bottom of the above figure. They correspond to two separate distinctions: single-machine versus multi-machine, and reliable versus unreliable.
On the first distinction:
* If the communicating systems run on the same machine, you may use one of the UNIX_
classes.
* For systems that run on different machines, you must use one of the NETWORK_
classes. This will also work if the systems are on the same machine, but less efficiently since communication may go through the network.
The use of the word UNIX_
does not mean that the machine must be running the Unix operating system; rather, it denotes a certain style of client-server communication, the Unix style. (This is comparable to the use of the name UNIX_FILE
in EiffelBase, for a class describing files that behave in the Unix style even though they may be implemented on non-Unix machines.)
The second distinction reflects two modes of socket communication: stream communication and datagram communication. Both of these modes support two-way communication between systems, but with different properties:
* A stream socket, as provided by the STREAM_
classes, provides sequenced communication without any loss or duplication of data. Stream communication is normally synchronous: the sending system waits until it has established a connection to the receiving system and transmitted the data.
* A datagram socket, as provided by the DATAGRAM_
classes, is asynchronous: the sending system emits its data and does not wait for an acknowledgment. Because the sender is not blocked, this mode is more efficient, but it does not guarantee sequencing, reliability or non-duplication.
===Sending and receiving simple values===
IO_MEDIUM
has all the basic input and output facilities applying to objects of basic types, as also offered in FILE(see the specification of FILE
in reference [ [[Bibliography|2]] ]). So you can use sockets to send and receive characters, integers, real numbers in simple or double precision and strings. For example, if the type of
`my_socket' is one of the socket classes shown on the preceding figures, any of the following calls will be valid:
my_socket.put_string ("Some text")
my_socket.read_integer_32
my_last_integer := my_socket.last_integer_32
Since sockets are bidirectional, these instructions may all appear as part of the same class provided you make sure to guarantee proper synchronization between senders and receivers. You may also prefer to specialize certain sockets for sending and others for receiving.
===Sending and receiving object structures===
In many cases, what you will want to send and receive is not just simple values but non-basic objects (instances of arbitrary classes, having as many fields as needed) and, more generally, entire object structures.
The basic mechanism enabling a system to send objects through EiffelNet is also the basic mechanism for storing objects into a file: class STORABLE
from EiffelBase.
{{note|Although this discussion uses the class STORABLE
, it should be noted that this class will in the future be made obsolete by the classes in the Serialization (SED) subcluster of EiffelBase. You will notice that the EiffelNet examples delivered with EiffelStudio use the classes from the Serialization cluster.}}
As documented in [ [[Bibliography|2]] ], STORABLE
provides features to store and retrieve complete object structures. There are three storage procedures, called under the respective forms
struct1.basic_store (iom1)
struct1.general_store (iom1)
struct1.independent_store (iom1)
Assuming that the type of ''iom1 ''is IO_MEDIUM
or a conforming type such as [[ref:libraries/base/reference/file_chart|FILE]] or one of the _SOCKET
classes, and that the type of ''struct1'' conforms to STORABLE
. Note that reference [2] in its original version does not include ''independent_store'', and requires ''iom'' to be of type FILE rather than the more general IO_MEDIUM
. The current version of EiffelBase, however, supports the more general properties described here.
All three storage procedures have the effect of sending to ''iom1 ''(whether a file, a socket or some other IO-medium) a copy of the entire object structure starting at ''struc1''. Together with the retrieval routines seen below, they apply the principle of reference completeness stated in [ [[Bibliography|1]] ] and [ [[Bibliography|2]] ]:
{| border="1"
|-
| Whenever a routine of class STORABLE
stores an object into an external file, it stores with it the dependents of that object.
| Whenever one of the associated retrieval routines retrieves a previously stored object, it also retrieves all its dependents.
|}
For EiffelNet, of course, "storing" and "retrieving" mean sending and receiving. The rest of this section, which applies to sockets as well as to files, will continue to use the original terminology of storage and retrieval.
The three storage procedures differ in their degree of generality:
* ''basic_store'' will only work if the sending and retrieving are performed by instances of the same system (the same executable module).
* ''general_store'' will work if the sender and retriever are different systems (using the same classes for the objects that they exchange), but these systems must run on machines of the same architecture, or at least of architectures that use the same data representation.
* ''independent_store'' will work in the most general case, with the sender and receiver possibly running on platforms using different data representations.
The penalty for using more general representations is that the data representation (as stored into the file or sent to the socket) will have to include more information. So ''basic_store ''uses the most compact representation, and ''independent_store'' the most verbose.
The scheme for accessing an object structure produced by one of these three procedures is the following, used in a descendant of class STORABLE
:
if attached {SOME_EXPECTED_TYPE} retrieved (iom2) as l_temp then
-- Retrieved object is of expected type and now attached to `l_temp'
-- Proceed with normal processing, typically involving calls of the form `l_temp.some_feature'
else
-- Retrieved was not attached to an object of SOME_EXPECTED_TYPE
end
Here ''iom2'' must be of a type conforming to IO_MEDIUM
. The [[ET: Inheritance#Object test|object test]] using the "attached" syntax checks that the root object of the structure produced by the corresponding call to one of the ''_store'' procedures is of a type that conforms to the expected type.
Although there are three separate storage procedures, there is only one retrieval routine, ''retrieved''; the algorithm for ''retrieved ''is able to figure out, from the format of the retrieved objects, whether they were produced in the basic, general or independent mode.
===Packets===
The classes PACKET
and DATAGRAM_PACKET
are used to represent packets of data that can be sent to sockets.
Their main use is for a system that relies on datagram communication. As noted above, this mode does not guarantee sequencing, making each system responsible for checking that packets arrive in the proper order. This is possible through feature ''number ''of class DATAGRAM_PACKET
, which gives the number of the current packet.
===Associating commands with events===
EiffelNet supports a highly asynchronous (and hence efficient) mode of operation by offering mechanisms through which you can specify that a certain action must be executed whenever a certain medium becomes available for reading, writing or handling of special cases (out of bounds). This facility is provided by a set of related classes:
* The actions are represented by class POLL_COMMAND
, an heir of the EiffelBase class COMMAND
with, in particular, the procedure ''execute''.
* Using MEDIUM_POLLER
, you can specify that a certain command (an instance of POLL_COMMAND
) must be executed whenever a certain medium becomes available for the appropriate operation (read, write, handling of out-of-bounds cases).
* Using POLL_MASK
, you can set a mask to select the sockets or files on which your instance of MEDIUM_POLLER
is working.