Socket
所需依赖项: io.ktor:ktor-network
, io.ktor:ktor-network-tls
代码示例: sockets-server, sockets-client, sockets-client-tls
除了服务器和客户端的 HTTP/WebSocket 处理外,Ktor 还支持 TCP 和 UDP 原始 socket。它公开了一个底层使用 java.nio 的挂起 API。
Socket 使用的是实验性的 API,预计会在未来的更新中演进,并可能带来破坏性变更。
添加依赖项
要使用 Sockets
,你需要在构建脚本中包含 ktor-network
artifact:
要在客户端使用安全 socket,你还需要添加 io.ktor:ktor-network-tls
。
服务端
创建服务端 socket
要构建服务端 socket,请创建 SelectorManager
实例,在其上调用 SocketBuilder.tcp()
函数,然后使用 bind
将服务端 socket 绑定到特定端口:
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
实例):
val socket = serverSocket.accept()
一旦你拥有了一个已连接的 socket,你就可以通过从 socket 读取或向 socket 写入来接收/发送数据。
接收数据
要从客户端接收数据,你需要调用 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
要释放与已连接 socket 相关联的资源,请调用 Socket.close
:
socket.close()
示例
下面的代码示例演示了如何在服务端使用 socket:
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
实例):
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
函数:
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 相关联的资源,请调用 Socket.close
和 SelectorManager.close
:
socket.close()
selectorManager.close()
示例
下面的代码示例演示了如何在客户端使用 socket:
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。