Events
There are several ways to send events between the server and the client.
Basic emit
Client
socket.emit("hello", "world");
Server
io.on('connection', (socket) => {
  socket.on('hello', (arg) => {
    console.log(arg); // world
  });
});
Listen for events
Server
io.on('connection', (socket) => {
  socket.emit('hello', 'world');
});
Client
socket.onEvent("hello") { args ->
    println(args[0]); // world
}
Acknowledgements
Events are great, but in some cases you may want a more classic request-response API. In Socket.IO, this feature is named acknowledgements.
You can add a callback as the last argument of the emit(), and this callback will be called once the other side acknowledges the event:
From client to server
Client
socket.emit("update item", 1, fun(data: ArrayList<JsonElement>) {
    val response = data[0] as JSONObject;
    println(response.getString("status")); // "ok"
})
Server
io.on('connection', (socket) => {
  socket.on('update item', (arg1, arg2, callback) => {
    console.log(arg1); // 1
    console.log(arg2); // { name: "updated" }
    callback({
      status: 'ok',
    });
  });
});
From server to client
Server
io.on('connection', (socket) => {
  socket.emit('hello', 'please acknowledge', (response) => {
    console.log(response); // prints "hi!"
  });
});
Client
socket.on("hello") { args, ack ->
    println(args[0]); // "please acknowledge"
    ack?.invoke("hi!");
}