Client-Server Communication In Distributed Systems

In the previous post I’ve covered main concepts of Interprocess Communication (IPC). Today we will get familiar with client-server paradigm and common communication methods used for it: sockets, RPC and pipes.

Client-server

Client-server concept underpins distributed systems over a couple of decades. There are two counterparts in the concept: a client and a server. In practice there are often multiple clients and single server. Clients start communication by sending requests to the server, the server handles them and usually returns responses back.

Client processes often do not live long, while server process, which is sometimes called daemon, live till OS shutdown.

Sockets

IPC with sockets is very common in distributed systems. In nutshell, a socket is a pair of an IP address and a port number. For two process to communicate, each of them needs a socket.

When server daemon is running on a host, it is listening to its port and handles all requests sent by clients to the port on the host (server socket). A client must know IP and port of the server (server socket) to send a request to it. Client’s port is often provided by OS kernel when client starts communication with the server and is freed when communication is over.

Although communication using sockets is common and efficient, it is considered low level, because sockets only allow to transfer unstructured stream of bytes between processes. It is up to client and server applications to impose a structure on the data passed as byte stream.

Remote Procedure Calls

RPC is a higher level communication method. It was designed to mimic procedure call mechanism, but execute it over network. RPC is conceptually similar to message passing IPC and is usually built on top of socket communication.

In contrast to IPC messages, RPC messages are well structured. Each message includes information about function to be executed and the parameters to be passed to that function. When the function is executed, a response with output is sent back to the requester in a separate message.

RPC hides the details of communication by providing a stub on the client side. When client needs to invoke a remote procedure, it invokes the stub and pass it the parameters. The stub marshals the parameters and sends a message to RPC daemon running on the server. RPC daemon (a similar stub on the server side) receives the message and invokes the procedure on the server. Return values are passed back to the client using the same technique.

Pipes

Pipe is one of the oldest and simplest IPC methods, that appeared in early UNIX systems. A pipe is an IPC abstraction with two endpoints, similar to a physical pipe. Usually one process puts data to one end of the pipe and another process consumes them from the other one.

Ordinary pipes

Ordinary pipes are unidirectional, i.e. allow only one-way communication. They implement standard producer-consumer mechanism, where one process writes to the pipe and another one reads from it. For two-way communication two pipes are needed.

Ordinary pipes require a parent–child relationship between communicating processes, because a pipe can only be accessed from process that created or inherited it. Parent process creates a pipe and uses it to communicate with a child created via fork(). Once communication is over and processes terminated, the ordinary pipe ceases to exist.

Named pipes

Named pipes are more powerful. They do not require parent–child relationship and can be bidirectional. Once a named pipe is created, multiple non related processes can communicate over it.

Named pipe continues to exist after communicating processes have terminated. It must be explicitly deleted when not required anymore.

Named pipes are known as FIFOs in UNIX systems and appear as files in the file system.