Skip to content
Server Plugin

通訊端

所需依賴項io.ktor:ktor-networkio.ktor:ktor-network-tls

程式碼範例sockets-serversockets-clientsockets-client-tls

原生伺服器
Ktor 支援 Kotlin/Native,允許您在沒有額外運行時或虛擬機器的情況下運行伺服器。
支援:✅

除了伺服器和用戶端的 HTTP/WebSocket 處理之外,Ktor 還支援 TCP 和 UDP 原始通訊端。它暴露了一個掛起式 API,底層使用 java.nio

通訊端使用實驗性 API,預計在即將到來的更新中會演進,並可能帶來重大變更。

新增依賴項

若要使用 Sockets,您需要在建置腳本中包含 ktor-network 構件:

Kotlin
Groovy
XML

若要在用戶端使用安全通訊端,您還需要新增 io.ktor:ktor-network-tls

伺服器

建立伺服器通訊端

若要建立伺服器通訊端,請建立 SelectorManager 實例,在其上呼叫 SocketBuilder.tcp() 函式,然後使用 bind 將伺服器通訊端繫結到特定連接埠:

kotlin
val selectorManager = SelectorManager(Dispatchers.IO)
val serverSocket = aSocket(selectorManager).tcp().bind("127.0.0.1", 9002)

上面的程式碼片段建立了一個 TCP 通訊端,它是 ServerSocket 實例。若要建立 UDP 通訊端,請使用 SocketBuilder.udp()

接受傳入連線

建立伺服器通訊端後,您需要呼叫 ServerSocket.accept 函式,它接受一個通訊端連線並返回一個已連線通訊端(一個 Socket 實例):

kotlin
val socket = serverSocket.accept()

一旦您擁有一個已連線通訊端,就可以透過從通訊端讀取或寫入來接收/傳送資料。

接收資料

若要從用戶端接收資料,您需要呼叫 Socket.openReadChannel 函式,它返回 ByteReadChannel

kotlin
val receiveChannel = socket.openReadChannel()

ByteReadChannel 提供了非同步讀取資料的 API。例如,您可以使用 ByteReadChannel.readUTF8Line 讀取一行 UTF-8 字元:

kotlin
val name = receiveChannel.readUTF8Line()

傳送資料

若要將資料傳送給用戶端,請呼叫 Socket.openWriteChannel 函式,它返回 ByteWriteChannel

kotlin
val sendChannel = socket.openWriteChannel(autoFlush = true)

ByteWriteChannel 提供了非同步寫入位元組序列的 API。例如,您可以使用 ByteWriteChannel.writeStringUtf8 寫入一行 UTF-8 字元:

kotlin
val name = receiveChannel.readUTF8Line()
sendChannel.writeStringUtf8("Hello, $name!
")

關閉通訊端

若要釋放與已連線通訊端相關聯的資源,請呼叫 Socket.close

kotlin
socket.close()

範例

以下程式碼範例展示了如何在伺服器端使用通訊端:

kotlin
package com.example

import io.ktor.network.selector.*
import io.ktor.network.sockets.*
import io.ktor.utils.io.*
import kotlinx.coroutines.*

fun main(args: Array<String>) {
    runBlocking {
        val selectorManager = SelectorManager(Dispatchers.IO)
        val serverSocket = aSocket(selectorManager).tcp().bind("127.0.0.1", 9002)
        println("Server is listening at ${serverSocket.localAddress}")
        while (true) {
            val socket = serverSocket.accept()
            println("Accepted $socket")
            launch {
                val receiveChannel = socket.openReadChannel()
                val sendChannel = socket.openWriteChannel(autoFlush = true)
                sendChannel.writeStringUtf8("Please enter your name
")
                try {
                    while (true) {
                        val name = receiveChannel.readUTF8Line()
                        sendChannel.writeStringUtf8("Hello, $name!
")
                    }
                } catch (e: Throwable) {
                    socket.close()
                }
            }
        }
    }
}

您可以在此處找到完整範例:sockets-server

用戶端

建立通訊端

若要建立用戶端通訊端,請建立 SelectorManager 實例,在其上呼叫 SocketBuilder.tcp() 函式,然後使用 connect 建立連線並取得一個已連線通訊端(一個 Socket 實例):

kotlin
val selectorManager = SelectorManager(Dispatchers.IO)
val socket = aSocket(selectorManager).tcp().connect("127.0.0.1", 9002)

一旦您擁有一個已連線通訊端,就可以透過從通訊端讀取或寫入來接收/傳送資料。

建立安全通訊端 (SSL/TLS)

安全通訊端允許您建立 TLS 連線。若要使用安全通訊端,您需要新增 ktor-network-tls 依賴項。 然後,在已連線通訊端上呼叫 Socket.tls 函式:

kotlin
val selectorManager = SelectorManager(Dispatchers.IO)
val socket = aSocket(selectorManager).tcp().connect("127.0.0.1", 8443).tls()

tls 函式允許您調整 TLSConfigBuilder 提供的 TLS 參數:

kotlin
val selectorManager = SelectorManager(Dispatchers.IO)
val socket = aSocket(selectorManager).tcp().connect("youtrack.jetbrains.com", port = 443).tls(coroutineContext = coroutineContext) {
    trustManager = object : X509TrustManager {
        override fun getAcceptedIssuers(): Array<X509Certificate?> = arrayOf()
        override fun checkClientTrusted(certs: Array<X509Certificate?>?, authType: String?) {}
        override fun checkServerTrusted(certs: Array<X509Certificate?>?, authType: String?) {}
    }
}

您可以在此處找到完整範例:sockets-client-tls

接收資料

若要從伺服器接收資料,您需要呼叫 Socket.openReadChannel 函式,它返回 ByteReadChannel

kotlin
val receiveChannel = socket.openReadChannel()

ByteReadChannel 提供了非同步讀取資料的 API。例如,您可以使用 ByteReadChannel.readUTF8Line 讀取一行 UTF-8 字元:

kotlin
val greeting = receiveChannel.readUTF8Line()

傳送資料

若要將資料傳送給伺服器,請呼叫 Socket.openWriteChannel 函式,它返回 ByteWriteChannel

kotlin
val sendChannel = socket.openWriteChannel(autoFlush = true)

ByteWriteChannel 提供了非同步寫入位元組序列的 API。例如,您可以使用 ByteWriteChannel.writeStringUtf8 寫入一行 UTF-8 字元:

kotlin
val myMessage = readln()
sendChannel.writeStringUtf8("$myMessage
")

關閉連線

若要釋放與已連線通訊端相關聯的資源,請呼叫 Socket.closeSelectorManager.close

kotlin
socket.close()
selectorManager.close()

範例

以下程式碼範例展示了如何在用戶端使用通訊端:

kotlin
package com.example

import io.ktor.network.selector.*
import io.ktor.network.sockets.*
import io.ktor.utils.io.*
import kotlinx.coroutines.*
import kotlin.system.*

fun main(args: Array<String>) {
    runBlocking {
        val selectorManager = SelectorManager(Dispatchers.IO)
        val socket = aSocket(selectorManager).tcp().connect("127.0.0.1", 9002)

        val receiveChannel = socket.openReadChannel()
        val sendChannel = socket.openWriteChannel(autoFlush = true)

        launch(Dispatchers.IO) {
            while (true) {
                val greeting = receiveChannel.readUTF8Line()
                if (greeting != null) {
                    println(greeting)
                } else {
                    println("Server closed a connection")
                    socket.close()
                    selectorManager.close()
                    exitProcess(0)
                }
            }
        }

        while (true) {
            val myMessage = readln()
            sendChannel.writeStringUtf8("$myMessage
")
        }
    }
}

您可以在此處找到完整範例:sockets-client