0
# WebSocket Support
1
2
Full-duplex WebSocket communication with extensions support, content conversion, and platform-specific optimizations for real-time applications.
3
4
## Capabilities
5
6
### WebSockets Plugin
7
8
Core WebSocket plugin providing client-side WebSocket functionality.
9
10
```kotlin { .api }
11
/**
12
* WebSocket client plugin for full-duplex communication
13
*/
14
object WebSockets : HttpClientPlugin<WebSockets.Config, WebSockets> {
15
override val key: AttributeKey<WebSockets> = AttributeKey("WebSocket")
16
17
/**
18
* WebSocket configuration
19
*/
20
class Config {
21
/** Ping interval in milliseconds (-1 to disable) */
22
var pingInterval: Long = -1L
23
24
/** Maximum frame size in bytes */
25
var maxFrameSize: Long = Long.MAX_VALUE
26
27
/** Content converter for serialization */
28
var contentConverter: WebsocketContentConverter? = null
29
30
/**
31
* Configure WebSocket extensions
32
*/
33
fun extensions(block: WebSocketExtensionsConfig.() -> Unit)
34
}
35
}
36
```
37
38
### WebSocket Connection Functions
39
40
Functions for establishing WebSocket connections with various configuration options.
41
42
```kotlin { .api }
43
/**
44
* Create WebSocket session with request configuration
45
*/
46
suspend fun HttpClient.webSocketSession(
47
block: HttpRequestBuilder.() -> Unit
48
): DefaultClientWebSocketSession
49
50
/**
51
* Create WebSocket session with URL components
52
*/
53
suspend fun HttpClient.webSocketSession(
54
method: HttpMethod = HttpMethod.Get,
55
host: String = "localhost",
56
port: Int = DEFAULT_PORT,
57
path: String = "/",
58
block: HttpRequestBuilder.() -> Unit = {}
59
): DefaultClientWebSocketSession
60
61
/**
62
* Create WebSocket session with URL string
63
*/
64
suspend fun HttpClient.webSocketSession(
65
urlString: String,
66
block: HttpRequestBuilder.() -> Unit = {}
67
): DefaultClientWebSocketSession
68
69
/**
70
* Use WebSocket with session handler
71
*/
72
suspend fun HttpClient.webSocket(
73
request: HttpRequestBuilder.() -> Unit = {},
74
block: suspend DefaultClientWebSocketSession.() -> Unit
75
)
76
77
/**
78
* Use WebSocket with URL and session handler
79
*/
80
suspend fun HttpClient.webSocket(
81
urlString: String,
82
request: HttpRequestBuilder.() -> Unit = {},
83
block: suspend DefaultClientWebSocketSession.() -> Unit
84
)
85
86
/**
87
* Use WebSocket with URL components
88
*/
89
suspend fun HttpClient.webSocket(
90
method: HttpMethod = HttpMethod.Get,
91
host: String = "localhost",
92
port: Int = DEFAULT_PORT,
93
path: String = "/",
94
request: HttpRequestBuilder.() -> Unit = {},
95
block: suspend DefaultClientWebSocketSession.() -> Unit
96
)
97
```
98
99
**Usage Examples:**
100
101
```kotlin
102
import io.ktor.client.plugins.websocket.*
103
import io.ktor.websocket.*
104
105
val client = HttpClient {
106
install(WebSockets) {
107
pingInterval = 20_000 // 20 seconds
108
maxFrameSize = 1024 * 1024 // 1MB
109
}
110
}
111
112
// Simple WebSocket usage
113
client.webSocket("wss://echo.websocket.org") {
114
send("Hello WebSocket!")
115
116
for (frame in incoming) {
117
when (frame) {
118
is Frame.Text -> {
119
val message = frame.readText()
120
println("Received: $message")
121
}
122
is Frame.Binary -> {
123
val data = frame.readBytes()
124
println("Received ${data.size} bytes")
125
}
126
is Frame.Close -> {
127
println("Connection closed")
128
break
129
}
130
else -> {}
131
}
132
}
133
}
134
135
// WebSocket session for manual control
136
val session = client.webSocketSession("wss://api.example.com/ws") {
137
headers["Authorization"] = "Bearer $token"
138
}
139
140
try {
141
session.send("Hello")
142
val frame = session.incoming.receive()
143
// Process frame
144
} finally {
145
session.close()
146
}
147
```
148
149
### WebSocket Session Interface
150
151
Interface for WebSocket communication sessions with frame handling.
152
153
```kotlin { .api }
154
/**
155
* Default client WebSocket session implementation
156
*/
157
interface DefaultClientWebSocketSession : ClientWebSocketSession {
158
/** Incoming frames channel */
159
val incoming: ReceiveChannel<Frame>
160
161
/** Outgoing frames channel */
162
val outgoing: SendChannel<Frame>
163
164
/** WebSocket extensions */
165
val extensions: List<WebSocketExtension<*>>
166
167
/**
168
* Send text frame
169
*/
170
suspend fun send(content: String)
171
172
/**
173
* Send binary frame
174
*/
175
suspend fun send(content: ByteArray)
176
177
/**
178
* Send frame
179
*/
180
suspend fun send(frame: Frame)
181
182
/**
183
* Close WebSocket connection
184
*/
185
suspend fun close(reason: CloseReason = CloseReason(CloseReason.Codes.NORMAL, ""))
186
187
/**
188
* Flush outgoing frames
189
*/
190
fun flush()
191
}
192
```
193
194
**Usage Examples:**
195
196
```kotlin
197
client.webSocket("wss://api.example.com/chat") {
198
// Send different types of content
199
send("Hello, World!") // Text frame
200
send(byteArrayOf(1, 2, 3, 4)) // Binary frame
201
send(Frame.Text("Custom text frame"))
202
send(Frame.Binary(true, byteArrayOf(5, 6, 7, 8)))
203
204
// Handle different frame types
205
for (frame in incoming) {
206
when (frame) {
207
is Frame.Text -> {
208
val text = frame.readText()
209
println("Text: $text")
210
211
// Echo back
212
send("Echo: $text")
213
}
214
is Frame.Binary -> {
215
val bytes = frame.readBytes()
216
println("Binary data: ${bytes.size} bytes")
217
}
218
is Frame.Ping -> {
219
println("Ping received")
220
// Pong is sent automatically
221
}
222
is Frame.Pong -> {
223
println("Pong received")
224
}
225
is Frame.Close -> {
226
val reason = frame.readReason()
227
println("Connection closed: ${reason?.message}")
228
break
229
}
230
}
231
}
232
}
233
```
234
235
### WebSocket Capabilities
236
237
Engine capabilities for WebSocket support and extensions.
238
239
```kotlin { .api }
240
/**
241
* Basic WebSocket support capability
242
*/
243
object WebSocketCapability : HttpClientEngineCapability<Unit>
244
245
/**
246
* WebSocket extensions support capability
247
*/
248
object WebSocketExtensionsCapability : HttpClientEngineCapability<List<WebSocketExtensionConfig>>
249
```
250
251
**Usage Examples:**
252
253
```kotlin
254
val client = HttpClient(CIO)
255
256
// Check WebSocket support
257
if (client.isSupported(WebSocketCapability)) {
258
println("WebSocket is supported by this engine")
259
260
// Use WebSocket functionality
261
client.webSocket("wss://api.example.com/ws") {
262
// WebSocket logic
263
}
264
} else {
265
println("WebSocket not supported")
266
}
267
268
// Check extensions support
269
if (client.isSupported(WebSocketExtensionsCapability)) {
270
println("WebSocket extensions are supported")
271
}
272
```
273
274
### Short Aliases
275
276
Convenient short aliases for WebSocket functions.
277
278
```kotlin { .api }
279
/**
280
* Short alias for webSocket function
281
*/
282
suspend fun HttpClient.ws(
283
urlString: String,
284
request: HttpRequestBuilder.() -> Unit = {},
285
block: suspend DefaultClientWebSocketSession.() -> Unit
286
) = webSocket(urlString, request, block)
287
288
/**
289
* Secure WebSocket connection (wss://)
290
*/
291
suspend fun HttpClient.wss(
292
host: String,
293
port: Int = 443,
294
path: String = "/",
295
request: HttpRequestBuilder.() -> Unit = {},
296
block: suspend DefaultClientWebSocketSession.() -> Unit
297
) = webSocket(HttpMethod.Get, host, port, path, request, block)
298
```
299
300
**Usage Examples:**
301
302
```kotlin
303
// Short alias
304
client.ws("wss://echo.websocket.org") {
305
send("Hello from ws!")
306
val response = (incoming.receive() as Frame.Text).readText()
307
println("Received: $response")
308
}
309
310
// Secure WebSocket with components
311
client.wss("api.example.com", 443, "/websocket") {
312
headers["Authorization"] = "Bearer $token"
313
} {
314
send("Authenticated message")
315
// Handle frames
316
}
317
```
318
319
### Content Conversion
320
321
Support for automatic serialization/deserialization of WebSocket messages.
322
323
```kotlin { .api }
324
/**
325
* WebSocket content converter interface
326
*/
327
interface WebsocketContentConverter {
328
/**
329
* Serialize object to WebSocket frame
330
*/
331
suspend fun serialize(
332
charset: Charset,
333
typeInfo: TypeInfo,
334
value: Any
335
): Frame
336
337
/**
338
* Deserialize WebSocket frame to object
339
*/
340
suspend fun deserialize(
341
charset: Charset,
342
typeInfo: TypeInfo,
343
content: Frame
344
): Any?
345
}
346
347
/**
348
* Send typed object (requires content converter)
349
*/
350
suspend inline fun <reified T> DefaultClientWebSocketSession.sendSerialized(data: T)
351
352
/**
353
* Receive typed object (requires content converter)
354
*/
355
suspend inline fun <reified T> DefaultClientWebSocketSession.receiveDeserialized(): T
356
```
357
358
**Usage Examples:**
359
360
```kotlin
361
import io.ktor.client.plugins.contentnegotiation.*
362
import io.ktor.serialization.kotlinx.json.*
363
import kotlinx.serialization.Serializable
364
365
@Serializable
366
data class ChatMessage(val user: String, val message: String, val timestamp: Long)
367
368
val client = HttpClient {
369
install(WebSockets) {
370
contentConverter = KotlinxWebsocketSerializationConverter(Json)
371
}
372
}
373
374
client.webSocket("wss://chat.example.com/room/123") {
375
// Send typed object
376
val message = ChatMessage("alice", "Hello everyone!", System.currentTimeMillis())
377
sendSerialized(message)
378
379
// Receive typed object
380
val receivedMessage: ChatMessage = receiveDeserialized()
381
println("${receivedMessage.user}: ${receivedMessage.message}")
382
}
383
```
384
385
### Error Handling
386
387
WebSocket-specific exception handling and error patterns.
388
389
```kotlin { .api }
390
/**
391
* Base WebSocket exception class
392
*/
393
open class WebSocketException(message: String) : IllegalStateException(message)
394
395
/**
396
* WebSocket connection failed exception
397
*/
398
class WebSocketConnectionException(message: String, cause: Throwable? = null)
399
: WebSocketException(message)
400
401
/**
402
* WebSocket close codes and reasons
403
*/
404
object CloseReason {
405
object Codes {
406
const val NORMAL = 1000
407
const val GOING_AWAY = 1001
408
const val PROTOCOL_ERROR = 1002
409
const val UNSUPPORTED_DATA = 1003
410
const val NO_STATUS = 1005
411
const val ABNORMAL_CLOSURE = 1006
412
const val INVALID_PAYLOAD = 1007
413
const val POLICY_VIOLATION = 1008
414
const val MESSAGE_TOO_BIG = 1009
415
const val MANDATORY_EXTENSION = 1010
416
const val INTERNAL_ERROR = 1011
417
const val TLS_HANDSHAKE_FAILED = 1015
418
}
419
}
420
421
data class CloseReason(val code: Short, val message: String)
422
```
423
424
**Usage Examples:**
425
426
```kotlin
427
try {
428
client.webSocket("wss://api.example.com/ws") {
429
send("Hello")
430
431
for (frame in incoming) {
432
when (frame) {
433
is Frame.Close -> {
434
val reason = frame.readReason()
435
when (reason?.code) {
436
CloseReason.Codes.NORMAL -> println("Normal close")
437
CloseReason.Codes.GOING_AWAY -> println("Server going away")
438
CloseReason.Codes.PROTOCOL_ERROR -> println("Protocol error")
439
else -> println("Close reason: ${reason?.message}")
440
}
441
break
442
}
443
// Handle other frames
444
else -> {}
445
}
446
}
447
}
448
} catch (e: WebSocketException) {
449
println("WebSocket error: ${e.message}")
450
} catch (e: WebSocketConnectionException) {
451
println("Connection failed: ${e.message}")
452
}
453
454
// Graceful close
455
client.webSocket("wss://api.example.com/ws") {
456
try {
457
// WebSocket communication
458
send("Hello")
459
} finally {
460
// Always close cleanly
461
close(CloseReason(CloseReason.Codes.NORMAL, "Client disconnecting"))
462
}
463
}
464
```