ソケット
必須の依存関係: io.ktor:ktor-network, io.ktor:ktor-network-tls
コード例: sockets-server, sockets-client, sockets-client-tls
Ktorは、サーバーおよびクライアント向けのHTTP/WebSocket処理に加えて、TCPおよびUDPの生ソケット(raw sockets)をサポートしています。 これは、内部で java.nio を使用するサスペンディングAPIを公開しています。
ソケットは実験的な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)上記のスニペットは、ServerSocket インスタンスであるTCPソケットを作成します。 UDPソケットを作成するには、SocketBuilder.udp() を使用します。
着信接続の受け入れ
サーバーソケットを作成した後、ソケット接続を受け入れ、接続されたソケット(Socket インスタンス)を返す ServerSocket.accept 関数を呼び出す必要があります。
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.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
クライアント
ソケットの作成
クライアントソケットを構築するには、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
