WebSocket client support for Ktor targeting the MinGW x64 platform, enabling native Windows applications built with Kotlin/Native to establish WebSocket connections.
pkg:gradle/io.ktor/ktor-client-websockets-mingwx64@3.2.x
npx @tessl/cli install tessl/gradle-io-ktor--ktor-client-websockets-mingwx64@3.2.0Ktor WebSocket client plugin for MinGW x64 platform, enabling native Windows applications built with Kotlin/Native to establish WebSocket connections. This plugin provides complete WebSocket client functionality including bidirectional communication, message serialization, connection lifecycle management, and ping/pong support for connection health monitoring.
implementation("io.ktor:ktor-client-websockets-mingwx64:3.2.0")import io.ktor.client.*
import io.ktor.client.plugins.websocket.*For WebSocket frames and session types:
import io.ktor.websocket.*For serialization support:
import io.ktor.websocket.serialization.*import io.ktor.client.*
import io.ktor.client.engine.winhttp.*
import io.ktor.client.plugins.websocket.*
import io.ktor.websocket.*
// Create client with WebSocket plugin
val client = HttpClient(WinHttp) {
install(WebSockets) {
pingInterval = 30.seconds
maxFrameSize = 1024 * 1024 // 1MB
}
}
// Connect and use WebSocket
client.webSocket(
method = HttpMethod.Get,
host = "echo.websocket.org",
port = 80,
path = "/"
) {
// Send text message
send(Frame.Text("Hello WebSocket!"))
// Receive message
for (frame in incoming) {
when (frame) {
is Frame.Text -> {
val message = frame.readText()
println("Received: $message")
}
is Frame.Binary -> {
val data = frame.readBytes()
println("Received binary data: ${data.size} bytes")
}
is Frame.Close -> {
println("Connection closed")
break
}
else -> {}
}
}
}
client.close()The Ktor WebSocket client plugin integrates with the Ktor HTTP client framework through several key components:
Install and configure the WebSocket plugin for your HttpClient instance.
fun HttpClientConfig<*>.WebSockets(config: WebSockets.Config.() -> Unit)
class WebSockets {
constructor()
constructor(pingIntervalMillis: Long, maxFrameSize: Long)
constructor(
pingIntervalMillis: Long,
maxFrameSize: Long,
extensionsConfig: WebSocketExtensionsConfig,
contentConverter: WebsocketContentConverter? = null
)
val pingIntervalMillis: Long
val maxFrameSize: Long
val contentConverter: WebsocketContentConverter?
}
fun WebSockets(
pingInterval: Duration?,
maxFrameSize: Long = Int.MAX_VALUE.toLong()
): WebSockets
class WebSockets.Config {
var pingIntervalMillis: Long
var maxFrameSize: Long
var pingInterval: Duration?
var contentConverter: WebsocketContentConverter?
fun extensions(block: WebSocketExtensionsConfig.() -> Unit)
}Create WebSocket connections using various methods - session-based for manual management or block-based for automatic cleanup.
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
)Establish secure WebSocket connections over SSL/TLS using the WSS protocol.
suspend fun HttpClient.wss(
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
)
suspend fun HttpClient.wss(
urlString: String,
request: HttpRequestBuilder.() -> Unit = {},
block: suspend DefaultClientWebSocketSession.() -> Unit
)Shorthand functions for WebSocket connections - ws aliases for standard connections.
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
)Client-specific WebSocket session interfaces providing access to the underlying HTTP call and session management.
interface ClientWebSocketSession : WebSocketSession {
val call: HttpClientCall
}
open class DefaultClientWebSocketSession(
override val call: HttpClientCall,
delegate: DefaultWebSocketSession
) : ClientWebSocketSession, DefaultWebSocketSession
val DefaultClientWebSocketSession.converter: WebsocketContentConverter?Automatic serialization and deserialization of custom types using configured content converters.
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 {
suspend fun serialize(
charset: Charset,
typeInfo: TypeInfo,
value: Any?
): Frame
suspend fun deserialize(
charset: Charset,
typeInfo: TypeInfo,
content: Frame
): Any?
fun isApplicable(frame: Frame): Boolean
}
suspend inline fun <reified T> WebsocketContentConverter.serialize(
value: T,
charset: Charset = Charsets.UTF_8
): Frame
suspend inline fun <reified T> WebsocketContentConverter.deserialize(
content: Frame,
charset: Charset = Charsets.UTF_8
): TCapability indicators for WebSocket support in HTTP client engines.
object WebSocketCapability : HttpClientEngineCapability<Unit>
object WebSocketExtensionsCapability : HttpClientEngineCapability<Unit>WebSocket-specific exception types for error handling.
class WebSocketException(message: String, cause: Throwable?) : IllegalStateException {
constructor(message: String)
}
open class WebsocketContentConvertException(
message: String,
cause: Throwable? = null
) : ContentConvertException
class WebsocketConverterNotFoundException(
message: String,
cause: Throwable? = null
) : WebsocketContentConvertException
class WebsocketDeserializeException(
message: String,
cause: Throwable? = null,
val frame: Frame
) : WebsocketContentConvertExceptionImportant constants used in WebSocket configuration.
const val PINGER_DISABLED: Long = 0Base WebSocket session interface from the shared websocket module.
interface WebSocketSession : CoroutineScope {
var masking: Boolean
var maxFrameSize: Long
val incoming: ReceiveChannel<Frame>
val outgoing: SendChannel<Frame>
val extensions: List<WebSocketExtension<*>>
suspend fun send(frame: Frame)
suspend fun flush()
}
class DefaultWebSocketSession : WebSocketSessionFrame types for different kinds of WebSocket messages.
sealed class Frame {
class Text(val data: ByteArray) : Frame {
constructor(text: String)
fun readText(): String
}
class Binary(val data: ByteArray) : Frame {
fun readBytes(): ByteArray
}
class Close(val data: ByteArray) : Frame {
constructor(reason: CloseReason?)
fun readReason(): CloseReason?
}
class Ping(val data: ByteArray) : Frame {
constructor()
}
class Pong(val data: ByteArray) : Frame {
constructor()
}
}
data class CloseReason(val code: Short, val message: String)Extension mechanism for WebSocket protocol extensions.
interface WebSocketExtension<ConfigType : Any> {
val factory: WebSocketExtensionFactory<ConfigType, out WebSocketExtension<ConfigType>>
val protocols: List<WebSocketExtensionHeader>
fun clientNegotiation(negotiatedProtocols: List<WebSocketExtensionHeader>): Boolean
fun serverNegotiation(requestedProtocols: List<WebSocketExtensionHeader>): List<WebSocketExtensionHeader>
fun processOutgoingFrame(frame: Frame): Frame
fun processIncomingFrame(frame: Frame): Frame
}
interface WebSocketExtensionFactory<ConfigType : Any, ExtensionType : WebSocketExtension<ConfigType>> {
val key: AttributeKey<ExtensionType>
val rsv1: Boolean
val rsv2: Boolean
val rsv3: Boolean
fun install(config: ConfigType.() -> Unit): ExtensionType
}
class WebSocketExtensionsConfig {
fun <ConfigType : Any> install(
extension: WebSocketExtensionFactory<ConfigType, *>,
config: ConfigType.() -> Unit = {}
)
fun build(): List<WebSocketExtension<*>>
}client.webSocket("wss://echo.websocket.org") {
// Send text message
send(Frame.Text("Hello WebSocket!"))
// Read response
val response = incoming.receive()
if (response is Frame.Text) {
println("Echo: ${response.readText()}")
}
}client.webSocket(host = "example.com", port = 8080, path = "/websocket") {
// Send binary data
val binaryData = byteArrayOf(1, 2, 3, 4, 5)
send(Frame.Binary(binaryData))
// Receive binary response
for (frame in incoming) {
when (frame) {
is Frame.Binary -> {
val receivedData = frame.readBytes()
println("Received ${receivedData.size} bytes")
}
is Frame.Close -> break
else -> {}
}
}
}val client = HttpClient(WinHttp) {
install(WebSockets) {
pingInterval = 30.seconds // Send ping every 30 seconds
maxFrameSize = 1024 * 1024 // 1MB max frame size
}
}
client.webSocket("wss://example.com/websocket") {
// Ping frames are sent automatically
// Connection will be kept alive with ping/pong
for (frame in incoming) {
when (frame) {
is Frame.Text -> {
println("Message: ${frame.readText()}")
}
is Frame.Ping -> {
// Pong is sent automatically
println("Ping received")
}
is Frame.Pong -> {
println("Pong received")
}
is Frame.Close -> {
println("Connection closed: ${frame.readReason()}")
break
}
else -> {}
}
}
}// Configure serialization
val client = HttpClient(WinHttp) {
install(WebSockets) {
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
}
client.webSocket("wss://api.example.com/websocket") {
// Send serialized object
sendSerialized(UserMessage("Hello", "user123"))
// Receive and deserialize
val response = receiveDeserialized<ServerResponse>()
println("Received: ${response.message}")
}try {
client.webSocket("wss://unreachable.example.com") {
send(Frame.Text("Hello"))
}
} catch (e: WebSocketException) {
println("WebSocket error: ${e.message}")
} catch (e: ConnectTimeoutException) {
println("Connection timeout")
} catch (e: Exception) {
println("General error: ${e.message}")
}