Skip to content

XArchived: Client server communication

eugene yokota edited this page Sep 10, 2017 · 1 revision

How should the client and server communicate?

Proposal 1: WebSocket requests, replies, and events

Use a stateful full-duplex connection

We could approach client-server in two broad ways:

  • discrete requests (like REST)
  • persistent connection (like WebSocket)

In the REST model, the server may have state but there isn't "connection state."

By using an always-open connection, clients and servers can immediately know when the other side dies. This allows the server to exit when there are no clients, and allows the client to restart the server as needed.

The always-open connection also allows an implementation of events, without resorting to polling.

WebSocket-over-HTTP specifically

Of course it's trivial to implement a bidirectional message stream with a raw socket. However, by using WebSocket we enable JavaScript clients.

Three kinds of message

  1. Requests: have a request ID to permit out-of-order replies, and a payload
  2. Replies: indicate the request ID they are the reply to, and have a payload
  3. Events: "unsolicited" messages (are not replied to), and have a payload

The request ID can simply be an incrementing serial so each thing that goes down the socket gets a number. If events also get a serial, it's an easy way to sort them by order of arrival.

It is probably useful in Scala to separate the envelope from the payload. The reason is that at the point of message creation, you don't know the envelope (for example, you would assign the request serial at the point of shoving the request down the socket, not at the point of request creation).

The envelope could also usefully include connection properties such as some identifier for the client, allowing the server to separate distinct clients.

type EnvelopeId
type PeerId

sealed trait Message
trait Request extends Message
trait Reply extends Message {
   def replyTo: (PeerId, EnvelopeId)
}
trait Event extends Message

case class Envelope[M <: Message](id: EnvelopeId, peer: PeerId, message: M)

Payload serialization

JSON is least-common-denominator, anything else is likely painful for non-Java clients.