使用Scala进行Socket.IO操作

背景 – 背景资料

如果你想要通过Socket.IO实现发布/订阅,我认为在Node.js上搭建服务器是一个可行的选择,但是有时候我们也希望在不同的系统之间进行协作。

用Scala编写Socket.IO

undefined

我尝试查找了一下是否存在支持 Socket.IO 的 Scala 库,但是我只发现了作为 Play Framework 模块存在的选项,没有找到通用的库。

这次服务器端使用了Akka HTTP进行编写,现在需要采用另一种方法进行实现。

使用Redis的发布/订阅功能

undefined

在Node.js端,只需要添加一些代码就可以进行以下适配。

const io = require('socket.io')(3000);
const redisAdapter = require('socket.io-redis');
io.adapter(redisAdapter({ host: 'localhost', port: 6379 }));

在Scala方面,需要自己编写(publish)来连接Redis。
我们将根据一篇关于Scala Redis客户端的文章进行选择。
参考来源于瀕死的たけぞう博客文章。

Sedis仅支持阻塞操作,所以排除掉。剩下的候选项是”scala-redis”或”rediscala”。

将要写入Redis的数据格式如下:
在这里,我们将把要发送的数据设置为data数组的第2个元素。

[
    "emitter",
    {
        "type": 2,
        "data": [
            "イベント名",
            {
                "message": "Hello World!"
            }
        ],
        "nsp": "namespace"
    },
    {
        "rooms": ["ルーム名"],
        "flags": []
    }
]

将使用MessagePack对其进行序列化的二进制数据写入redis。
在这里,由于先前的库“scala-redis”没有二进制写入方法,所以只能选择“rediscala”。

在Scala中,我们使用由MessagePack官方提供的”msgpack-scala”库。

这个库有点混乱,表示上述JSON的代码如下。
其他语言的库似乎可以通过一个方法将其转换为二进制,但在这个库中我没有找到…

    val out = new ByteArrayOutputStream
    val packer = MessagePack.newDefaultPacker(out)

    packer.packArrayHeader(3)

    // set emitter
    packer.packString("emitter")

    // set type 2
    packer.packMapHeader(3)
    packer.packString("type")
    packer.packString("2")

    // set data
    packer.packString("data")
    packer.packArrayHeader(2)

    // set event name
    packer.packString("イベント名")

    // set data body
    packer.packMapHeader(1)
    packer.packString("message")
    packer.packString("Hello World!")

    // set namespace
    packer.packString("nsp")
    packer.packString("/")

    packer.packMapHeader(2)
    packer.packString(roomName)
    packer.packArrayHeader(1)
    packer.packString("ルーム名")
    packer.packString("flags")
    packer.packMapHeader(0)

    packer.flush()
    packer.close()

    out.toByteArray

我們將使用rediscala將在此處獲取的二進制數據寫入Redis。
※RedisClient的構造函數已經以隱含方式接收ActorSystem,因此請根據各自的環境進行準備。

   val redis = RedisClient(server,port)
   redis.publish("チャンネル名", バイナリデータ)

数据接收

クライアント側では、設定したイベント名でデータを受信することができます。

socketio.on('イベント名', function(msg){
        console.log('receive:' +  JSON.stringify(msg));
    });

总结

通过使用其他语言的相同机制,我们可以将数据写入Redis来实现与Scala介绍的相同功能。

※本次参考的网站

这个人用Python实现了类似的功能。
使用Python向socket.io-redis发射事件。

广告
将在 10 秒后关闭
bannerAds