Search code examples
kotlinserverktor

Generate a random port numbers everytime a new server instance is created


I am trying to create a Ktor Server which currently runs on localhost. When i run only one instance of the server on terminal it is working fine, but when i open a new tab on terminal and run another instance of the same server i get this Warning/Error:

Exception in thread "main" java.net.BindException: Address already in use
        at sun.nio.ch.Net.bind0(Native Method)
        at sun.nio.ch.Net.bind(Net.java:461)
        at sun.nio.ch.Net.bind(Net.java:453)
        at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:222)
        at io.netty.channel.socket.nio.NioServerSocketChannel.doBind(NioServerSocketChannel.java:134)
        at io.netty.channel.AbstractChannel$AbstractUnsafe.bind(AbstractChannel.java:562)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.bind(DefaultChannelPipeline.java:1334)
        at io.netty.channel.AbstractChannelHandlerContext.invokeBind(AbstractChannelHandlerContext.java:506)
        at io.netty.channel.AbstractChannelHandlerContext.bind(AbstractChannelHandlerContext.java:491)
        at io.netty.channel.DefaultChannelPipeline.bind(DefaultChannelPipeline.java:973)
        at io.netty.channel.AbstractChannel.bind(AbstractChannel.java:260)
        at io.netty.bootstrap.AbstractBootstrap$2.run(AbstractBootstrap.java:356)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.ktor.server.netty.EventLoopGroupProxy$Companion$create$factory$1$1.run(NettyApplicationEngine.kt:241)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(Thread.java:748)

This happens because the server is using the port which is already in use.

What i am trying to achieve, is that the server should generate a unique port number for the second instance automatically. I am not sure how to do this on Ktor.

This is the current configuration of my server:

fun main() {
    val env = applicationEngineEnvironment {
        module {
            main()
        }
        connector {
            host = "localhost"
            port = 8080
        }

    }
    embeddedServer(Netty, env).start(true)
}

Solution

  • You can use ServerSocket to automatically allocate a port number and close that socket. Here is an example:

    import io.ktor.server.engine.*
    import io.ktor.server.netty.*
    import io.ktor.application.*
    import io.ktor.response.*
    import io.ktor.routing.*
    import java.net.ServerSocket
    
    fun main(args: Array<String>) {
        embeddedServer(Netty, port = getFreePort()) {
            routing {
                get("/") {
                    call.respondText { "Hello" }
                }
            }
        }.start()
    }
    
    fun getFreePort(): Int {
        val socket = ServerSocket(0)
        val port = socket.localPort
        socket.close()
        return port
    }
    

    Also, there is an up for grabs feature request to allocate a random port number out of the box.