Raw Sockets
Table of contents:
This functionality is exposed through the artifact.
In order to create either server or client sockets, you have to use the aSocket
builder,with a mandatory ActorSelectorManager
: aSocket(selector)
. For example: aSocket(ActorSelectorManager(Dispatchers.IO))
.
Then use:
val socketBuilder = aSocket(selector).tcp()
for a builder using TCP socketsval socketBuilder = aSocket(selector).udp()
for a builder using UDP sockets
This returns a SocketBuilder
that can be used to:
val serverSocket = aSocket(selector).tcp().bind(address)
to listen to an address (for servers)val clientSocket = aSocket(selector).tcp().connect(address)
to connect to an address (for clients)
Once you have a socket
open by either binding or the builder,you can read from or write to the socket, by opening read/write channels:
val input : ByteReadChannel = socket.openReadChannel()
val output: ByteWriteChannel = socket.openWriteChannel(autoFlush = true)
You can read the KDoc for ByteReadChanneland for further information on the available methods.
When creating a server socket, you have to bind
to a specific SocketAddress
to geta ServerSocket
:
val server = aSocket(selector).tcp().bind(InetSocketAddress("127.0.0.1", 2323))
The server socket has an accept
method that returns, one at a time, a connected socket for each incoming connection pending in the backlog:
If you want to support multiple clients at once, remember to call launch { }
to preventthe function that is accepting the sockets from suspending.
fun main(args: Array<String>) {
runBlocking {
println("Started echo telnet server at ${server.localAddress}")
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()
}
}
}
}
Then you can connect to it using telnet and start typing:
For each line that you type (you have to press the return key), the server will replywith the same line:
When creating a socket client, you have to connect
to a specific SocketAddress
to geta 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'")
}
}
Ktor supports secure sockets. To enable them you will need to include theio.ktor:ktor-network-tls:$ktor_version
artifact, and call the .tls()
to a connected socket.
You can adjust a few optional parameters for the TLS connection:
suspend fun Socket.tls(
trustManager: X509TrustManager? = null,
randomAlgorithm: String = "NativePRNGNonBlocking",
serverName: String? = null,
coroutineContext: CoroutineContext = Dispatchers.IO