通訊端
所需依賴項:io.ktor:ktor-network
、io.ktor:ktor-network-tls
程式碼範例: sockets-server、 sockets-client、 sockets-client-tls
除了伺服器和用戶端的 HTTP/WebSocket 處理之外,Ktor 還支援 TCP 和 UDP 原始通訊端。它暴露了一個掛起式 API,底層使用 java.nio。
通訊端使用實驗性 API,預計在即將到來的更新中會演進,並可能帶來重大變更。
新增依賴項
若要使用 Sockets
,您需要在建置腳本中包含 ktor-network
構件:
若要在用戶端使用安全通訊端,您還需要新增 io.ktor:ktor-network-tls
。
伺服器
建立伺服器通訊端
若要建立伺服器通訊端,請建立 SelectorManager
實例,在其上呼叫 SocketBuilder.tcp()
函式,然後使用 bind
將伺服器通訊端繫結到特定連接埠:
val selectorManager = SelectorManager(Dispatchers.IO)
val serverSocket = aSocket(selectorManager).tcp().bind("127.0.0.1", 9002)
上面的程式碼片段建立了一個 TCP 通訊端,它是 ServerSocket 實例。若要建立 UDP 通訊端,請使用 SocketBuilder.udp()
。
接受傳入連線
建立伺服器通訊端後,您需要呼叫 ServerSocket.accept
函式,它接受一個通訊端連線並返回一個已連線通訊端(一個 Socket 實例):
val socket = serverSocket.accept()
一旦您擁有一個已連線通訊端,就可以透過從通訊端讀取或寫入來接收/傳送資料。
接收資料
若要從用戶端接收資料,您需要呼叫 Socket.openReadChannel
函式,它返回 ByteReadChannel:
val receiveChannel = socket.openReadChannel()
ByteReadChannel
提供了非同步讀取資料的 API。例如,您可以使用 ByteReadChannel.readUTF8Line
讀取一行 UTF-8 字元:
val name = receiveChannel.readUTF8Line()
傳送資料
若要將資料傳送給用戶端,請呼叫 Socket.openWriteChannel
函式,它返回 ByteWriteChannel:
val sendChannel = socket.openWriteChannel(autoFlush = true)
ByteWriteChannel
提供了非同步寫入位元組序列的 API。例如,您可以使用 ByteWriteChannel.writeStringUtf8
寫入一行 UTF-8 字元:
val name = receiveChannel.readUTF8Line()
sendChannel.writeStringUtf8("Hello, $name!
")
關閉通訊端
若要釋放與已連線通訊端相關聯的資源,請呼叫 Socket.close
:
socket.close()
範例
以下程式碼範例展示了如何在伺服器端使用通訊端:
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 實例):
val selectorManager = SelectorManager(Dispatchers.IO)
val socket = aSocket(selectorManager).tcp().connect("127.0.0.1", 9002)
一旦您擁有一個已連線通訊端,就可以透過從通訊端讀取或寫入來接收/傳送資料。
建立安全通訊端 (SSL/TLS)
安全通訊端允許您建立 TLS 連線。若要使用安全通訊端,您需要新增 ktor-network-tls 依賴項。 然後,在已連線通訊端上呼叫 Socket.tls
函式:
val selectorManager = SelectorManager(Dispatchers.IO)
val socket = aSocket(selectorManager).tcp().connect("127.0.0.1", 8443).tls()
tls
函式允許您調整 TLSConfigBuilder 提供的 TLS 參數:
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:
val receiveChannel = socket.openReadChannel()
ByteReadChannel
提供了非同步讀取資料的 API。例如,您可以使用 ByteReadChannel.readUTF8Line
讀取一行 UTF-8 字元:
val greeting = receiveChannel.readUTF8Line()
傳送資料
若要將資料傳送給伺服器,請呼叫 Socket.openWriteChannel
函式,它返回 ByteWriteChannel:
val sendChannel = socket.openWriteChannel(autoFlush = true)
ByteWriteChannel
提供了非同步寫入位元組序列的 API。例如,您可以使用 ByteWriteChannel.writeStringUtf8
寫入一行 UTF-8 字元:
val myMessage = readln()
sendChannel.writeStringUtf8("$myMessage
")
關閉連線
若要釋放與已連線通訊端相關聯的資源,請呼叫 Socket.close
和 SelectorManager.close
:
socket.close()
selectorManager.close()
範例
以下程式碼範例展示了如何在用戶端使用通訊端:
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。