iT邦幫忙

2025 iThome 鐵人賽

DAY 8
0

除了常見的 HTTP 協定之外,面對不同的需求,在後端有時候也會需要處理其他的協定。

今天我們來看怎麼用 Ktor 處理 websocket 的需求

什麼是 websocket

類似於 HTTP 通訊協定,WebSockets 也是一種通訊協定。不過不一樣的地方是,它可以在用戶端和伺服器之間建立一個持久、雙向的連線。所以在後端的邏輯上,不同於 HTTP 接收到請求,處理好回傳之後就沒事了。websocket 通常會需要建立一個長期存在的進程或線程,來持續的維持這個雙向連線。

很幸運的,由於 Ktor 本身非常善用 coroutine 來建立非同步的服務,所以在維持雙向連線上的語法也非常的單純。我們只需要引用 Ktor 的 WebSocket 套件,就可以完成這個任務

安裝 WebSocket 套件

跟前面的套件一樣,在建立專案時可以從官網內點選 WebSocket 套件並安裝。

如果要在既有專案上建立,一樣可以在 build.gradle.kts 加上

implementation("io.ktor:ktor-websockets:$ktor_version")

然後重新 build 整個專案。

安裝並重新引入之後,我們就可以開始使用 WebSocket 套件了。

我們來看看官方提供的範例

package com.example

import io.ktor.server.application.*
import io.ktor.server.html.*
import io.ktor.server.http.content.*
import io.ktor.server.plugins.di.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import java.time.Duration
import kotlin.random.Random
import kotlin.time.Duration.Companion.seconds
import kotlinx.html.*

fun Application.configureSockets() {
    install(WebSockets) {
        pingPeriod = 15.seconds
        timeout = 15.seconds
        maxFrameSize = Long.MAX_VALUE
        masking = false
    }
    routing {
        webSocket("/echo") {
            send("Please enter your name")
            for (frame in incoming) {
                frame as? Frame.Text ?: continue
                val receivedText = frame.readText().trim()
                if (receivedText.equals("bye", ignoreCase = true)) {
                    close(CloseReason(CloseReason.Codes.NORMAL, "Client said BYE"))
                } else {
                    send(Frame.Text("Hi, $receivedText!"))
                }
            }
        }
    }
}

這邊我們看到,由於建立的是一個持續的連線,所以我們需要一個迴圈來不斷地從 incoming 這個 ReceiveChannel 物件接收對話。

接收進來的資料以 Frame 作為單位,這邊我們假設收到的都會是純文字,所以試著將 frame 轉換成 Frame.Text

一直到我們對話輸入 bye 之後,伺服器才會中斷連線。

運作起來之後,我們就可以用 websocket 測試工具來測試這個功能。我個人的習慣是使用指令列工具 websocat 測試

在 mac 上的安裝可以用 brew

brew install websocat

安裝好之後, 我們就可以測試我們的 ws://0.0.0.0:8080/echo 路由了

websocat ws://0.0.0.0:8080/echo

Please enter your name
recca
Hi, recca!
alice
Hi, alice!
bye
^C

今天的內容就到這邊,我們明天見!


上一篇
Day 07:Ktor 的依賴注入
下一篇
Day 09:Ktor 壓縮回應
系列文
每天一點 Ktor 3.0:一個月學會 Kotlin 後端開發11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言