ソケット
必須依存関係: io.ktor:ktor-network
, io.ktor:ktor-network-tls
コード例: sockets-server, sockets-client, sockets-client-tls
サーバーとクライアントにおけるHTTP/WebSocket処理に加えて、KtorはTCPおよびUDPのrawソケットをサポートしています。Ktorは、内部で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()
接続されたソケットを取得したら、ソケットから読み書きすることでデータを受送信できます。
データを受信する
クライアントからデータを受信するには、ByteReadChannelを返すSocket.openReadChannel
関数を呼び出す必要があります。
val receiveChannel = socket.openReadChannel()
ByteReadChannel
はデータの非同期読み取りのためのAPIを提供します。例えば、ByteReadChannel.readUTF8Line
を使用してUTF-8文字の行を読み取ることができます。
val name = receiveChannel.readUTF8Line()
データを送信する
クライアントにデータを送信するには、ByteWriteChannelを返すSocket.openWriteChannel
関数を呼び出します。
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")
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で確認できます。
データを受信する
サーバーからデータを受信するには、ByteReadChannelを返すSocket.openReadChannel
関数を呼び出す必要があります。
val receiveChannel = socket.openReadChannel()
ByteReadChannel
はデータの非同期読み取りのためのAPIを提供します。例えば、ByteReadChannel.readUTF8Line
を使用してUTF-8文字の行を読み取ることができます。
val greeting = receiveChannel.readUTF8Line()
データを送信する
サーバーにデータを送信するには、ByteWriteChannelを返すSocket.openWriteChannel
関数を呼び出します。
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で確認できます。