Communications in Client Server Systems
A socket is an endpoint for communication. It’s an IP address concatenated with a port number. In general, sockets use a client server architecture. The server listens to a specified port, and when a request is received, a connection is established with the client socket. Ports below 1024 are considered well-known, and standard services are implemented on them. When a client process initiates a connection, the client computer assigns a port greater than 1024 to it. If we assume that the connection is to a web server, the following connection is created:
All connections must be unique, so another process on the same client accessing the same web server would have a different port number (greater than 1024).
Socket based communication is common and efficient, but is considered low-level because it exchanges an unstructured stream of bytes. The client and server applications are responsible for imposing structure on the data.
Remote Procedure Calls
RPC was designed as a way to simulate a procedure call, but work over two systems sharing a network connection. It’s similar to Message-based IPC systems, but uses well structured messages, not just packets of data. Each message is sent to an RPC daemon listening on a specific port of the remote system, and contains the name and the parameters of the function to execute. The function on the remote machine is then executed as requested, and the output values are sent back to the requester in another message.
RPCs allow a client to invoke remote procedures as if they were local calls. The details of the communication mechanism is hidden. The client side program contains a stub, one for each remote procedure. The stub decides which server port to send the data to, and marshals (packs into a network transmittable form) the parameters. Then a message is passed to the server side with all this data. The server side stub unmarshalls the message, and invokes the procedure requested. Any return values are similarly marshalled and sent back to the client.
Big-endian, small-endian: When communicating over networks, the potentially different data representations used by client and server machines have to be dealt with. To resolve these issues, many RPC systems define a machine-independent representation of data, such as XDR (external data representation). Machine-dependent data is converted into XDR before being transmitted, and re-converted into a machine-dependent representation at the receiving end.
Failure to execute calls: Unlike local procedure calls, which rarely fail, RPCs can fail or be duplicated and executed multiple times due to common network errors. One mechanism to prevent this is “at most once”. A timestamp is attached to each message before being sent, and the server end keeps track of all the timestamps of messages it has already processed. Any duplicate messages are ignored. Therefore the client can safely send a message one or more times and be assured it only executes once. In addition to this, we need to remove the chance that the server might not receive the request at all. To do this, the server sends an ACK message whenever an RPC call is received and executed. The client will periodically resend the RPC call until an ACK is received. This is the mechanism known as “exactly once”.
Port binding information: The client needs to know the port of the server on which the RPC service is available, so that it can establish a connection. This is difficult since the client doesn’t have full information about the server. We could a) have predetermined information (fixed ports), which cannot be changed once the program is compiled, or b) we could use a dynamic binding mechanism, using a matchmaker. The matchmaker daemon runs on a fixed port, and the client can send a message to it with the name of the RPC and get the port address of that RPC in return. This mechanism needs a little extra overhead for the initial request, but is much more flexible than having fixed port addresses.
Remote Method Invocation
RMI is a Java language feature similar to RPCs. It allows a thread to invoke a method on a remote object (an object that resides in a different JVM). While RPCs support procedural programming (calling remote functions) and passing ordinary data structures as parameters, RMIs allow you to invoke methods on remote objects, and pass objects as parameters. RMIs allow you to develop Java applications that are distributed across a network.
RMI implements the remote object using stubs and skeletons. A stub represents the remote object on the client side, and creates a parcel consisting of the name of the remote object’s method, and the marshalled parameters for it. The stub sends the parcel to the server and the skeleton of the remote object unmarshalls the parameters and invokes the requested method. Any return values or exceptions are then marshalled into a parcel and sent back to the client, where the stub handles it.
Some rules to note about parameter passing:
- If the marshalled parameters are local objects, they are passed by value (in a method known as object serialization). But if they are also remote objects, they are passed by reference.
- If local objects are to be passed as marshalled parameters, they must implement the Java language interface java.io.Serializable, which allows the state of an object to be written to a byte stream.