3

While trying to create a large number of websockets I get a java.net.BindException. I think this is because the websockets are not being properly closed.

How do I properly close a websocket in kotlin?

Example code in a single file:

import io.ktor.application.*
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.features.websocket.*
import io.ktor.http.*
import io.ktor.http.cio.websocket.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.websocket.*
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Semaphore

const val port = 8080
const val WEBSOCKET_ROUTE = "/ws"
const val TOTAL_REQUESTS = 100000
const val CONCURRENT_REQUESTS = 100

fun main(args: Array<String>) = runBlocking {
    val embeddedServer = embeddedServer(Netty, port = port, module = modules)
    embeddedServer.start()

    runClients()

    embeddedServer.stop(0, 0)
}

private suspend fun runClients() = coroutineScope {

    val client = HttpClient(CIO) {
        install(io.ktor.client.features.websocket.WebSockets)
    }

    val semaphore = Semaphore(CONCURRENT_REQUESTS)
    val clientJobs = List(TOTAL_REQUESTS) {
        semaphore.acquire()
        launch {
            makeClientWebSocketRequest(client, it)
            semaphore.release()
        }
    }

    clientJobs.joinAll()
}

private suspend fun makeClientWebSocketRequest(client: HttpClient, id: Int) {
    client.webSocket(method = HttpMethod.Get, "localhost", port, WEBSOCKET_ROUTE) {
        try {
            send(Frame.Text("ehlo $id"))
            val data = (incoming.receive() as Frame.Text).readText()
            println("client: $data")
        } finally {
            close()
        }
    }
}

val modules = fun Application.() {
    install(io.ktor.websocket.WebSockets)

    routing {
        webSocket(WEBSOCKET_ROUTE) {
            handleWebSocketServer(this)
        }
    }
}

private suspend fun handleWebSocketServer(websocket: DefaultWebSocketServerSession) {
    try {
        val data = (websocket.incoming.receive() as Frame.Text).readText()
        println("server: $data")
        websocket.outgoing.send(Frame.Text(data.reversed()))
    } finally {
        websocket.close()
    }
}

Exception:

Exception in thread "main" java.net.BindException: Address already in use: no further information

netstat output:

PS C:\Users\partkyle> netstat

Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    127.0.0.1:8080         kubernetes:55278       TIME_WAIT
  TCP    127.0.0.1:49152        kubernetes:8080        TIME_WAIT
  TCP    127.0.0.1:49153        kubernetes:8080        TIME_WAIT
  TCP    127.0.0.1:49154        kubernetes:8080        TIME_WAIT
  TCP    127.0.0.1:49155        kubernetes:8080        TIME_WAIT
  TCP    127.0.0.1:49156        kubernetes:8080        TIME_WAIT
  TCP    127.0.0.1:49157        kubernetes:8080        TIME_WAIT

......
partkyle
  • 1,458
  • 1
  • 15
  • 25

0 Answers0