fritz2 offers support for websockets you can use with different protocols.
First create a socket:
val websocket: Socket = websocket("ws://myserver:3333")
You can specify one or more protocols on creation. See these docs for more information.
Your socket is now ready to establish a Session with the server, using the method connect(). Messages can now be
exchanged between socket and server, which looks like this:
val session: Session = websocket("ws://...").connect()
// receiving messages from server
session.messages.body handledBy {
    window.alert("Server said: $it")
}
// sending messages to server
session.send("Hello")
As you can see, Session offers a Flow of MessageEvents in messages. When a new message from the server arrives,
a new message pops up on the Flow. Get the content of the message with one of the following methods (depending on
content type):
data(): Flow<Any?>body(): Flow<String>blob(): Flow<Blob>arrayBuffer(): Flow<ArrayBuffer>More information regarding the connection status is provided by the Session as Flows:
isConnecting: Flow<Boolean>isOpen: Flow<Boolean>isClosed: Flow<Boolean>opens: Flow<Event>closes: Flow<CloseEvent>When you're done, close the session client-side. Supplying a code and a reason is optional.
session.close(reason = "finished")
After the Session was closed by either client or server, no further messages can be sent, and trying to do so
throws a SendException.
You can synchronize the content of a Store with a server via websockets. You can use a function like
syncWith(socket: Socket, resource: Resource<T, I>) in the following example:
@Lenses
@Serializable
data class Person(val name: String = "", val age: Int = -1, val _id: String = Id.next())
fun Store<Person>.syncWith(socket: Socket) {
    val session = socket.connect()
    var last: Person? = null
    apply {
        session.messages.body.map {
            val received = Json.decodeFromString(Person.serializer(), it)
            last = received
            received
        } handledBy this@syncWith.update
        this@syncWith.data.drop(1) handledBy {
            if (last != it) session.send(Json.encodeToString(Person.serializer(), it))
        }
    }
}
val socket = websocket("ws://...")
val entityStore = object : RootStore<Person>(Person(), job = Job()) {
    init {
        syncWith(socket, PersonResource)
    }
    // your handlers...
}
When the model in the Store changes, it will be sent to the server via Websockets, and vice versa of course.
For a full working example have a look at our Ktor Chat
project.