ソケット
必須依存関係: io.ktor:ktor-network, io.ktor:ktor-network-tls
コード例: sockets-server, sockets-client, sockets-client-tls
Ktorは、サーバーとクライアントにおけるHTTP/WebSocket処理に加えて、TCPおよびUDPのrawソケットをサポートしています。 内部で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で確認できます。
