Ktor client WebSocket plugin for Windows x64 platform providing native WebSocket communication capabilities
npx @tessl/cli install tessl/maven-io-ktor--ktor-client-websockets-mingwx64@2.3.0Ktor Client WebSockets provides WebSocket client functionality for the Ktor framework, specifically compiled for Windows x64 using the MinGW toolchain. This plugin enables asynchronous WebSocket communication in Kotlin Multiplatform applications targeting native Windows applications.
build.gradle.kts dependenciesdependencies {
implementation("io.ktor:ktor-client-websockets-mingwx64:2.3.13")
}import io.ktor.client.*
import io.ktor.client.plugins.websocket.*
import io.ktor.websocket.*For engine-specific functionality (requires additional dependencies):
import io.ktor.client.engine.cio.*For serialization support:
import io.ktor.serialization.*import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.websocket.*
import io.ktor.websocket.*
val client = HttpClient(CIO) {
install(WebSockets) {
pingInterval = 20_000
maxFrameSize = Long.MAX_VALUE
}
}
// Connect to WebSocket server
client.webSocket(
method = HttpMethod.Get,
host = "echo.websocket.org",
port = 80,
path = "/"
) {
// Send text message
send("Hello WebSocket!")
// Receive and process messages
for (frame in incoming) {
when (frame) {
is Frame.Text -> {
val message = frame.readText()
println("Received: $message")
}
is Frame.Binary -> {
println("Received binary data")
}
is Frame.Close -> {
println("Connection closed")
break
}
else -> {}
}
}
}
client.close()The Ktor WebSocket client is built around several key components:
Note: Raw WebSocket sessions (without automatic ping-pong handling) require additional engine-specific dependencies like ktor-client-cio and are not included in this core WebSocket client package.
Core WebSocket plugin setup with customizable connection parameters and extensions support.
fun HttpClientConfig<*>.WebSockets(config: WebSockets.Config.() -> Unit)
class WebSockets.Config {
var pingInterval: Long
var maxFrameSize: Long
var contentConverter: WebsocketContentConverter?
fun extensions(block: WebSocketExtensionsConfig.() -> Unit)
}The WebSockets plugin must be installed on the HttpClient to enable WebSocket functionality. Configuration options include:
pingInterval: Interval between ping frames in milliseconds (-1L to disable)maxFrameSize: Maximum frame size in bytes (default: Long.MAX_VALUE)contentConverter: Optional converter for serialization/deserializationextensions: Configuration block for WebSocket extensionsval client = HttpClient(CIO) {
install(WebSockets) {
pingInterval = 30_000 // Send ping every 30 seconds
maxFrameSize = 16 * 1024 * 1024 // 16MB max frame size
contentConverter = KotlinxWebsocketSerializationConverter(Json)
extensions {
// Configure WebSocket extensions
}
}
}Managed WebSocket sessions with automatic ping-pong handling and connection lifecycle management.
suspend fun HttpClient.webSocketSession(
block: HttpRequestBuilder.() -> Unit
): DefaultClientWebSocketSession
suspend fun HttpClient.webSocketSession(
method: HttpMethod = HttpMethod.Get,
host: String? = null,
port: Int? = null,
path: String? = null,
block: HttpRequestBuilder.() -> Unit = {}
): DefaultClientWebSocketSession
suspend fun HttpClient.webSocketSession(
urlString: String,
block: HttpRequestBuilder.() -> Unit = {}
): DefaultClientWebSocketSession
suspend fun HttpClient.webSocket(
request: HttpRequestBuilder.() -> Unit,
block: suspend DefaultClientWebSocketSession.() -> Unit
)
suspend fun HttpClient.webSocket(
method: HttpMethod = HttpMethod.Get,
host: String? = null,
port: Int? = null,
path: String? = null,
request: HttpRequestBuilder.() -> Unit = {},
block: suspend DefaultClientWebSocketSession.() -> Unit
)
suspend fun HttpClient.webSocket(
urlString: String,
request: HttpRequestBuilder.() -> Unit = {},
block: suspend DefaultClientWebSocketSession.() -> Unit
)
interface ClientWebSocketSession : WebSocketSession {
val call: HttpClientCall
}
class DefaultClientWebSocketSession(
call: HttpClientCall,
delegate: DefaultWebSocketSession
) : ClientWebSocketSession, DefaultWebSocketSessionThe WebSocket connection functions provide different ways to establish and manage WebSocket connections:
webSocketSession(): Returns a session object for manual managementwebSocket(): Executes a block with automatic session cleanupExample establishing a session:
val session = client.webSocketSession(
method = HttpMethod.Get,
host = "localhost",
port = 8080,
path = "/websocket"
) {
header("Authorization", "Bearer token")
}
// Use session...
session.close()Example with automatic cleanup:
client.webSocket("wss://api.example.com/stream") {
send("subscribe:user-events")
for (frame in incoming) {
if (frame is Frame.Text) {
val data = frame.readText()
handleMessage(data)
}
}
} // Session automatically closedSecure WebSocket (WSS) support for encrypted connections using SSL/TLS.
suspend fun HttpClient.wss(
request: HttpRequestBuilder.() -> Unit,
block: suspend DefaultClientWebSocketSession.() -> Unit
)
suspend fun HttpClient.wss(
urlString: String,
request: HttpRequestBuilder.() -> Unit = {},
block: suspend DefaultClientWebSocketSession.() -> Unit
)
suspend fun HttpClient.wss(
method: HttpMethod = HttpMethod.Get,
host: String? = null,
port: Int? = null,
path: String? = null,
request: HttpRequestBuilder.() -> Unit = {},
block: suspend DefaultClientWebSocketSession.() -> Unit
)Secure WebSocket functions automatically use WSS protocol and default to port 443:
client.wss(
host = "secure.example.com",
path = "/websocket"
) {
send("Hello secure WebSocket!")
val response = incoming.receive()
if (response is Frame.Text) {
println("Secure response: ${response.readText()}")
}
}Shorthand functions for common WebSocket operations.
suspend fun HttpClient.ws(
method: HttpMethod = HttpMethod.Get,
host: String? = null,
port: Int? = null,
path: String? = null,
request: HttpRequestBuilder.() -> Unit = {},
block: suspend DefaultClientWebSocketSession.() -> Unit
)
suspend fun HttpClient.ws(
request: HttpRequestBuilder.() -> Unit,
block: suspend DefaultClientWebSocketSession.() -> Unit
)
suspend fun HttpClient.ws(
urlString: String,
request: HttpRequestBuilder.() -> Unit = {},
block: suspend DefaultClientWebSocketSession.() -> Unit
)The ws() functions are shortcuts for webSocket() functions:
// These are equivalent:
client.ws("ws://localhost:8080/echo") { /* ... */ }
client.webSocket("ws://localhost:8080/echo") { /* ... */ }Structured data serialization and deserialization for WebSocket messages.
val DefaultClientWebSocketSession.converter: WebsocketContentConverter?
suspend fun DefaultClientWebSocketSession.sendSerialized(
data: Any?,
typeInfo: TypeInfo
)
suspend inline fun <reified T> DefaultClientWebSocketSession.sendSerialized(
data: T
)
suspend fun <T> DefaultClientWebSocketSession.receiveDeserialized(
typeInfo: TypeInfo
): T
suspend inline fun <reified T> DefaultClientWebSocketSession.receiveDeserialized(): T
interface WebsocketContentConverter {
// Converter implementation details
}Content serialization requires a configured contentConverter in the WebSockets plugin:
@Serializable
data class ChatMessage(val user: String, val text: String, val timestamp: Long)
val client = HttpClient(CIO) {
install(WebSockets) {
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
}
client.webSocket("ws://chat.example.com") {
// Send structured data
sendSerialized(ChatMessage("alice", "Hello!", System.currentTimeMillis()))
// Receive structured data
val message = receiveDeserialized<ChatMessage>()
println("${message.user}: ${message.text}")
}WebSocket-specific exceptions for error handling and connection management.
class WebSocketException(
message: String,
cause: Throwable? = null
) : IllegalStateException
class WebsocketConverterNotFoundException(
message: String,
cause: Throwable? = null
) : WebsocketContentConvertException
class WebsocketDeserializeException(
message: String,
cause: Throwable? = null,
val frame: Frame
) : WebsocketContentConvertException
open class WebsocketContentConvertException(
message: String,
cause: Throwable? = null
) : ContentConvertExceptionCommon exception scenarios:
try {
client.webSocket("ws://unreachable.example.com") {
send("test")
}
} catch (e: WebSocketException) {
println("WebSocket error: ${e.message}")
} catch (e: ConnectTimeoutException) {
println("Connection timeout")
}
try {
val data = receiveDeserialized<MyData>()
} catch (e: WebsocketConverterNotFoundException) {
println("No converter configured for serialization")
} catch (e: WebsocketDeserializeException) {
println("Failed to deserialize message: ${e.message}")
println("Frame type: ${e.frame?.frameType}")
}WebSocket engine capability detection and platform-specific features.
object WebSocketCapability : HttpClientEngineCapability<Unit>
object WebSocketExtensionsCapability : HttpClientEngineCapability<Unit>Capability checking for engine compatibility:
val client = HttpClient(CIO)
// Check if engine supports WebSockets
val supportsWebSockets = client.engine.supportedCapabilities
.contains(WebSocketCapability)
// Check if engine supports WebSocket extensions
val supportsExtensions = client.engine.supportedCapabilities
.contains(WebSocketExtensionsCapability)
if (supportsWebSockets) {
// Proceed with WebSocket operations
} else {
throw IllegalStateException("Engine does not support WebSockets")
}This package is specifically compiled for Windows x64 using the MinGW toolchain, providing:
The WebSocket client works with different Ktor engines on MinGW x64:
For MinGW x64 target, both CIO and WinHttp engines provide WebSocket functionality. Raw WebSocket sessions require additional engine-specific extensions not included in this core package.
Common error scenarios and handling patterns:
try {
client.webSocket("ws://invalid-host") { /* ... */ }
} catch (e: UnresolvedAddressException) {
// Handle DNS resolution failure
} catch (e: ConnectException) {
// Handle connection refused
} catch (e: WebSocketException) {
// Handle WebSocket protocol errors
}client.webSocket("ws://echo.websocket.org") {
try {
send("Hello")
val frame = incoming.receive()
// Process frame
} catch (e: ClosedReceiveChannelException) {
// Connection closed by peer
} catch (e: CancellationException) {
// Operation cancelled
}
}try {
val data = receiveDeserialized<MyType>()
} catch (e: WebsocketConverterNotFoundException) {
// No content converter configured
} catch (e: WebsocketDeserializeException) {
// Failed to deserialize - check frame type
when (e.frame?.frameType) {
FrameType.TEXT -> // Handle text frame error
FrameType.BINARY -> // Handle binary frame error
else -> // Handle other frame types
}
}