Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A very simple example of an echo-server using the non-blocking Java I/O APIs
package se.hellsoft.nonblocking.echo
import java.net.InetSocketAddress
import java.nio.ByteBuffer
import java.nio.channels.SelectionKey
import java.nio.channels.Selector
import java.nio.channels.ServerSocketChannel
import java.nio.channels.SocketChannel
/**
* A simple non-blocking echo server.
*
* To test this, start the application and use something like netcat to connect to the port (9191)
*/
fun main() {
val selector = Selector.open()
val buffer = ByteBuffer.allocate(1024)
val serverChannel = ServerSocketChannel.open()
serverChannel.configureBlocking(false)
serverChannel.bind(InetSocketAddress(9191))
serverChannel.register(selector, SelectionKey.OP_ACCEPT)
selector.selectNow()
while (true) {
val count = selector.select()
println("Selected $count channels!")
val selectedKeys = selector.selectedKeys()
selectedKeys.forEach {
if (!it.isValid) {
println("Invalid key - cancel it!")
it.cancel()
return@forEach
}
try {
when {
it.isAcceptable -> { // New connection on our ServerSocketChannel
val sc = it.channel() as ServerSocketChannel
val newClient = sc.accept()
if (newClient != null) {
println("New client!")
newClient.configureBlocking(false)
newClient.register(selector, SelectionKey.OP_READ)
}
}
it.isReadable && it.isReadInteresting -> { // Incoming data on a SocketChannel
val socket = it.channel() as SocketChannel
if (socket.isConnected) {
socket.read(buffer)
buffer.flip()
val content = ByteArray(buffer.limit())
buffer.get(content)
val text = String(content, Charsets.UTF_8)
if (text.isNotEmpty()) {
println("Received: $text")
socket.register(selector, SelectionKey.OP_WRITE, content)
}
buffer.rewind()
}
}
it.isWritable && it.isWriteInteresting -> { // SocketChannel ready for writing
val socket = it.channel() as SocketChannel
if (socket.isConnected) {
val content = it.attachment() as ByteArray
buffer.put(content)
println("Wrote ${String(content, Charsets.UTF_8)} on channel")
buffer.flip()
socket.write(buffer)
socket.register(selector, SelectionKey.OP_READ, null)
buffer.rewind()
}
}
}
} catch (e: Exception) {
println("Closing channel!")
it.channel().close()
}
}
}
}
val SelectionKey.isReadInteresting
get() = this.interestOps() and SelectionKey.OP_READ == SelectionKey.OP_READ
val SelectionKey.isWriteInteresting
get() = this.interestOps() and SelectionKey.OP_WRITE == SelectionKey.OP_WRITE
@moldovean

This comment has been minimized.

Copy link

@moldovean moldovean commented Sep 7, 2020

How is this non-blocking?

selector.selectNow() -> is non blocking: it will almost never have anything.

while (true) {
    val count = selector.select()

selector.select() -> is blocking, so it will wait until at least one selector is selected, while(true) is redundant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.