Raw Sockets

预计阅读时间:4分钟

除了对服务器客户端进行HTTP处理外,Ktor还支持客户端和服务器,TCP和UDP原始套接字. 它公开了在后台使用NIO的悬浮API.

目录:

Sockets

此功能通过io.ktor:ktor-network:$ktor_version工件io.ktor:ktor-network:$ktor_version .

为了创建服务器或客户端套接字,必须使用带有强制性ActorSelectorManageraSocket(selector)aSocket构建aSocket(selector) . 例如: aSocket(ActorSelectorManager(Dispatchers.IO)) .

然后使用:

  • val socketBuilder = aSocket(selector).tcp()用于使用TCP套接字的构建器
  • val socketBuilder = aSocket(selector).udp()用于使用UDP套接字的构建器

这将返回一个SocketBuilder ,可用于:

  • val serverSocket = aSocket(selector).tcp().bind(address)侦听地址(对于服务器)
  • val clientSocket = aSocket(selector).tcp().connect(address)连接到一个地址(对于客户端)

如果需要控制套接字使用的调度程序,则可以实例化选择器,该选择器使用例如缓存的线程池:

val exec = Executors.newCachedThreadPool()
val selector = ActorSelectorManager(exec.asCoroutineDispatcher())
val tcpSocketBuilder = aSocket(selector).tcp()

一旦你有一个socket由要么开放结合连接的建筑商,你可以从或写入套接字读取,通过打开读/写通道:

val input : ByteReadChannel  = socket.openReadChannel()
val output: ByteWriteChannel = socket.openWriteChannel(autoFlush = true)

您可以阅读KDoc的ByteReadChannelByteWriteChannel以获得有关可用方法的更多信息.

Server

创建服务器套接字时,必须bind到特定的SocketAddress以获得ServerSocket

val server = aSocket(selector).tcp().bind(InetSocketAddress("127.0.0.1", 2323))

服务器套接字具有一个accept方法,该方法一次为积压中待处理的每个传入连接返回一个连接的套接字:

val socket = server.accept()

如果要一次支持多个客户端,请记住调用launch { }以防止正在接受套接字的函数挂起.

Simple Echo Server:

echo-server.kt
fun main(args: Array<String>) {
    runBlocking {
        val server = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().bind(InetSocketAddress("127.0.0.1", 2323))
        println("Started echo telnet server at ${server.localAddress}")
        
        while (true) {
            val socket = server.accept()
            
            launch {
                println("Socket accepted: ${socket.remoteAddress}")
                
                val input = socket.openReadChannel()
                val output = socket.openWriteChannel(autoFlush = true)
                
                try {
                    while (true) {
                        val line = input.readUTF8Line()
                        
                        println("${socket.remoteAddress}: $line")
                        output.writeBytes("$line\r\n")
                    }
                } catch (e: Throwable) {
                    e.printStackTrace()
                    socket.close()
                }
            }
        }
    }
}

然后,您可以使用telnet连接到它并开始输入:

telnet 127.0.0.1 2323

对于您键入的每一行(您必须按回车键),服务器将以同一行答复:

Trying 127.0.0.1...
Connected to 127.0.0.1
Escape character is '^]'.

Hello
Hello
World
World
|

Client

创建套接字客户端时,必须connect到特定的SocketAddress以获得Socket

val socket = aSocket(selector).tcp().connect(InetSocketAddress("127.0.0.1", 2323))

Simple Client Connecting to an Echo Server:

echo-client.kt
fun main(args: Array<String>) {
    runBlocking {
        val socket = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().connect(InetSocketAddress("127.0.0.1", 2323))
        val input = socket.openReadChannel()
        val output = socket.openWriteChannel(autoFlush = true)

        output.writeBytes("hello\r\n")
        val response = input.readUTF8Line()
        println("Server said: '$response'")
    }
}

Secure Sockets (SSL/TLS)

Ktor支持安全套接字. 要启用它们,您将需要包含io.ktor:ktor-network-tls:$ktor_version工件,然后将.tls()调用到已连接的套接字.

连接到安全插座:

runBlocking {
    val socket = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().connect(InetSocketAddress("google.com", 443)).tls()
    val w = socket.openWriteChannel(autoFlush = false)
    w.write("GET / HTTP/1.1\r\n")
    w.write("Host: google.com\r\n")
    w.write("\r\n")
    w.flush()
    val r = socket.openReadChannel()
    println(r.readUTF8Line())
}

您可以为TLS连接调整一些可选参数:

suspend fun Socket.tls(
        trustManager: X509TrustManager? = null,
        randomAlgorithm: String = "NativePRNGNonBlocking",
        serverName: String? = null,
        coroutineContext: CoroutineContext = Dispatchers.IO
): Socket

by  ICOPY.SITE