Skip to content
Server Plugin

Socket

所需依赖项: io.ktor:ktor-network, io.ktor:ktor-network-tls

代码示例: sockets-server, sockets-client, sockets-client-tls

原生服务器
Ktor supports Kotlin/Native and allows you to run a server without an additional runtime or virtual machine.
支持: ✅

除了服务器和客户端的 HTTP/WebSocket 处理外,Ktor 还支持 TCP 和 UDP 原始 socket。它公开了一个底层使用 java.nio 的挂起 API。

Socket 使用的是实验性的 API,预计会在未来的更新中演进,并可能带来破坏性变更。

添加依赖项

要使用 Sockets,你需要在构建脚本中包含 ktor-network artifact:

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 写入来接收/发送数据。

接收数据

要从客户端接收数据,你需要调用 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")
            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 写入来接收/发送数据。

创建安全 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