buenomini

IPC vs RPC

Both let processes talk to each other. IPC makes you deal with the sockets, RPC hides them behind function calls.

3 min readsystems-programming

IPC (inter-process communication) and RPC (remote procedure call) solve the same problem, getting processes to talk to each other, just at very different levels of abstraction.

IPC is the low-level mechanism. You open connections, send messages and receive responses yourself, over sockets (TCP, UDP, Unix domain sockets), pipes, message queues or shared memory. And you're in charge of everything: connection management, serialization, error handling, protocol design.

RPC is built on top of IPC (usually sockets) and makes remote calls look like local function calls:

// Looks like a local function call
let result = remote_server.getUserData(user_id);

Underneath, the function call gets serialized to a message, sent via a socket (IPC), executed remotely, and the result comes back, gets deserialized and is returned to the caller. You pretend it's local.

# What that looks like for a key-value store

The IPC version is what I'm building. A CLI tool you run like zkv connect --addr 127.0.0.1:6379:

$ zkv connect
Connected to zkv server
> SET mykey myvalue
OK
> GET mykey
myvalue

What happens:

  1. CLI opens a TCP socket connection
  2. User types SET key value
  3. CLI encodes it into wire protocol format
  4. Sends bytes over socket
  5. Receives response bytes
  6. Decodes and prints response
  7. Connection stays open for more commands

I manage the socket, the protocol and the encoding/decoding. All of it.

The RPC version would be a library you include in your code:

use zkv::Client;

let client = Client::connect("127.0.0.1:6379")?;
client.set("mykey", "myvalue")?;
let value = client.get("mykey")?;

The library establishes the socket connection internally, client.set() gets serialized to the protocol format and sent over the socket, the response is deserialized and returned as a typed value, and the library handles the connection management. You never see any of it, you just call functions.

The usual examples are gRPC (define services in Protocol Buffers, generate client/server code, call methods, and it runs on HTTP/2 over TCP sockets), JSON-RPC (HTTP requests with JSON payloads that map to function calls) and Apache Thrift, which is similar to gRPC with a different IDL and wire protocol.

# Which one to use

IPC when you want full control over the protocol, when you're building a CLI tool or custom client, when it's a performance-critical path and you don't want the abstraction overhead, or when you want to learn how things work underneath (that's me).

RPC when you want simple function-call semantics, when you're building a library for others to use, when type safety matters (generated code from schemas) or when you need multiple languages. gRPC has 10+ language bindings.

So RPC trades control for convenience. You get the simple API, type safety from a schema, and connection pooling, retries and timeouts handled for you. You give up control over the wire format, visibility into what's happening on the network, and some performance to the extra layers. For most applications that's a good deal I think. For learning systems programming, IPC teaches you more.

My zkv project is IPC-based, a CLI that manages TCP sockets directly, and with it I'm learning socket programming, wire protocol design, message framing and connection handling. Could I wrap it in an RPC library later? Sure. But if you learn the IPC layer first RPC stops being magic, and if you start with RPC you might never understand what's happening on the wire.