Skip to content
Server Plugin

Socket

必要相依性io.ktor:ktor-network, io.ktor:ktor-network-tls

程式碼範例sockets-server, sockets-client, sockets-client-tls

Native 伺服器
Ktor 支援 Kotlin/Native,並允許您在沒有額外執行階段或虛擬機的情況下執行伺服器。
支援:✅

除了伺服器與用戶端的 HTTP/WebSocket 處理外,Ktor 還支援 TCP 與 UDP 原始 Socket。 它提供了一個暫停式 API,底層使用的是 java.nio

Socket 使用的是實驗性 API,預計在未來的更新中會有所演進,並可能包含破壞性變更。

新增相依性

若要使用 Sockets,您需要在組建指令碼中包含 ktor-network 構件:

Kotlin
Groovy
XML

若要在用戶端使用安全 Socket,您還需要加入 io.ktor:ktor-network-tls

伺服器

建立伺服器 Socket

若要建立伺服器 Socket,請建立 SelectorManager 執行個體,對其呼叫 SocketBuilder.tcp() 函式,然後使用 bind 將伺服器 Socket 繫結至特定埠:

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

上述程式碼片段建立了一個 TCP Socket,即 ServerSocket 執行個體。 若要建立 UDP Socket,請使用 SocketBuilder.udp()

接受傳入連線

建立伺服器 Socket 後,您需要呼叫 ServerSocket.accept 函式,該函式會接受 Socket 連線並傳回一個已連線的 Socket(Socket 執行個體):

kotlin
val socket = serverSocket.accept()

取得已連線的 Socket 後,您就可以透過讀取或寫入該 Socket 來接收/傳送資料。

接收資料

若要從用戶端接收資料,您需要呼叫 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

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

kotlin
socket.close()

範例

下方的程式碼範例示範了如何在伺服器端使用 Socket:

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.remoteAddress}")
            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

用戶端

建立 Socket

若要建立用戶端 Socket,請建立 SelectorManager 執行個體,對其呼叫 SocketBuilder.tcp() 函式,然後使用 connect 建立連線並取得一個已連線的 Socket(Socket 執行個體):

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

取得已連線的 Socket 後,您就可以透過讀取或寫入該 Socket 來接收/傳送資料。

建立安全 Socket (SSL/TLS)

安全 Socket 允許您建立 TLS 連線。 若要使用安全 Socket,您需要加入 ktor-network-tls 相依性。 然後,在已連線的 Socket 上呼叫 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 相關聯的資源,請呼叫 Socket.closeSelectorManager.close

kotlin
socket.close()
selectorManager.close()

範例

下方的程式碼範例示範了如何在用戶端端使用 Socket:

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