Skip to content
Server Plugin

ソケット

必須依存関係: io.ktor:ktor-network, io.ktor:ktor-network-tls

コード例: sockets-server, sockets-client, sockets-client-tls

ネイティブサーバー
KtorはKotlin/Nativeをサポートしており、追加のランタイムや仮想マシンなしでサーバーを実行できます。
のサポート: ✅

サーバーとクライアントにおけるHTTP/WebSocket処理に加えて、KtorはTCPおよびUDPのrawソケットをサポートしています。Ktorは、内部でjava.nioを使用するサスペンドAPIを公開しています。

ソケットは実験的なAPIを使用しており、今後のアップデートで破壊的変更が行われる可能性があります。

依存関係を追加する

Socketsを使用するには、ビルドスクリプトにktor-networkアーティファクトを含める必要があります。

Kotlin
Groovy
XML

クライアントでセキュアソケットを使用するには、io.ktor:ktor-network-tlsも追加する必要があります。

サーバー

サーバーソケットを作成する

サーバーソケットを構築するには、SelectorManagerインスタンスを作成し、その上でSocketBuilder.tcp()関数を呼び出し、bindを使用してサーバーソケットを特定のポートにバインドします。

kotlin
val selectorManager = SelectorManager(Dispatchers.IO)
val serverSocket = aSocket(selectorManager).tcp().bind("127.0.0.1", 9002)

上記のスニペットは、ServerSocketインスタンスであるTCPソケットを作成します。UDPソケットを作成するには、SocketBuilder.udp()を使用します。

着信接続を受け入れる

サーバーソケットを作成した後、ソケット接続を受け入れ、接続されたソケット(Socketインスタンス)を返すServerSocket.accept関数を呼び出す必要があります。

kotlin
val socket = serverSocket.accept()

接続されたソケットを取得したら、ソケットから読み書きすることでデータを受送信できます。

データを受信する

クライアントからデータを受信するには、ByteReadChannelを返すSocket.openReadChannel関数を呼び出す必要があります。

kotlin
val receiveChannel = socket.openReadChannel()

ByteReadChannelはデータの非同期読み取りのためのAPIを提供します。例えば、ByteReadChannel.readUTF8Lineを使用してUTF-8文字の行を読み取ることができます。

kotlin
val name = receiveChannel.readUTF8Line()

データを送信する

クライアントにデータを送信するには、ByteWriteChannelを返すSocket.openWriteChannel関数を呼び出します。

kotlin
val sendChannel = socket.openWriteChannel(autoFlush = true)

ByteWriteChannelはバイトシーケンスの非同期書き込みのためのAPIを提供します。例えば、ByteWriteChannel.writeStringUtf8を使用してUTF-8文字の行を書き込むことができます。

kotlin
val name = receiveChannel.readUTF8Line()
sendChannel.writeStringUtf8("Hello, $name!
")

ソケットを閉じる

接続されたソケットに関連付けられたリソースを解放するには、Socket.closeを呼び出します。

kotlin
socket.close()

以下のコードサンプルは、サーバーサイドでソケットを使用する方法を示しています。

kotlin
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インスタンス)を取得します。

kotlin
val selectorManager = SelectorManager(Dispatchers.IO)
val socket = aSocket(selectorManager).tcp().connect("127.0.0.1", 9002)

接続されたソケットを取得したら、ソケットから読み書きすることでデータを受送信できます。

セキュアソケットを作成する (SSL/TLS)

セキュアソケットを使用すると、TLS接続を確立できます。セキュアソケットを使用するには、ktor-network-tlsの依存関係を追加する必要があります。 その後、接続されたソケットでSocket.tls関数を呼び出します。

kotlin
val selectorManager = SelectorManager(Dispatchers.IO)
val socket = aSocket(selectorManager).tcp().connect("127.0.0.1", 8443).tls()

tls関数を使用すると、TLSConfigBuilderによって提供されるTLSパラメーターを調整できます。

kotlin
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関数を呼び出す必要があります。

kotlin
val receiveChannel = socket.openReadChannel()

ByteReadChannelはデータの非同期読み取りのためのAPIを提供します。例えば、ByteReadChannel.readUTF8Lineを使用してUTF-8文字の行を読み取ることができます。

kotlin
val greeting = receiveChannel.readUTF8Line()

データを送信する

サーバーにデータを送信するには、ByteWriteChannelを返すSocket.openWriteChannel関数を呼び出します。

kotlin
val sendChannel = socket.openWriteChannel(autoFlush = true)

ByteWriteChannelはバイトシーケンスの非同期書き込みのためのAPIを提供します。例えば、ByteWriteChannel.writeStringUtf8を使用してUTF-8文字の行を書き込むことができます。

kotlin
val myMessage = readln()
sendChannel.writeStringUtf8("$myMessage
")

接続を閉じる

接続されたソケットに関連付けられたリソースを解放するには、Socket.closeSelectorManager.closeを呼び出します。

kotlin
socket.close()
selectorManager.close()

以下のコードサンプルは、クライアントサイドでソケットを使用する方法を示しています。

kotlin
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で確認できます。