0
# Utilities
1
2
Ktor Network provides a comprehensive set of utility functions, extensions, and helper classes that simplify common socket operations and provide convenient abstractions for networking tasks.
3
4
## Socket Extension Functions
5
6
### Lifecycle Extensions
7
8
```kotlin { .api }
9
val ASocket.isClosed: Boolean
10
11
suspend fun ASocket.awaitClosed()
12
```
13
14
Extensions for monitoring socket lifecycle state.
15
16
**Properties:**
17
- `isClosed: Boolean` - Returns true if the socket has been closed
18
19
**Methods:**
20
- `suspend fun awaitClosed()` - Suspends the current coroutine until the socket is closed
21
22
### I/O Channel Extensions
23
24
```kotlin { .api }
25
fun AReadable.openReadChannel(): ByteReadChannel
26
27
fun AWritable.openWriteChannel(autoFlush: Boolean = false): ByteWriteChannel
28
```
29
30
Extensions for opening I/O channels on readable and writable sockets.
31
32
**AReadable Extensions:**
33
- `openReadChannel(): ByteReadChannel` - Opens a dedicated read channel for receiving data
34
35
**AWritable Extensions:**
36
- `openWriteChannel(autoFlush: Boolean = false): ByteWriteChannel` - Opens a dedicated write channel for sending data
37
- `autoFlush: Boolean` - Whether to automatically flush written data (default: false)
38
39
### Connection Utility
40
41
```kotlin { .api }
42
fun Socket.connection(): Connection
43
```
44
45
Creates a convenient Connection wrapper for TCP sockets.
46
47
**Returns:** `Connection` - A wrapper containing both input and output channels
48
49
### Server Socket Extensions
50
51
```kotlin { .api }
52
val ServerSocket.port: Int
53
```
54
55
Extension property to get the port number from a server socket.
56
57
**Returns:** `Int` - The port number the server socket is bound to
58
59
## Connection Wrapper Class
60
61
### Connection Class
62
63
```kotlin { .api }
64
class Connection(
65
val socket: Socket,
66
val input: ByteReadChannel,
67
val output: ByteWriteChannel
68
) : Closeable {
69
override fun close()
70
}
71
```
72
73
Convenience class that combines a socket with its I/O channels for easier handling.
74
75
**Properties:**
76
- `socket: Socket` - The underlying TCP socket
77
- `input: ByteReadChannel` - Read channel for receiving data
78
- `output: ByteWriteChannel` - Write channel for sending data
79
80
**Methods:**
81
- `close()` - Closes the connection and all associated resources
82
83
## Type of Service (QoS)
84
85
### TypeOfService Value Class
86
87
```kotlin { .api }
88
@JvmInline
89
value class TypeOfService(val value: UByte) {
90
constructor(value: Int) : this(value.toUByte())
91
92
val intValue: Int get() = value.toInt()
93
94
companion object {
95
val UNDEFINED: TypeOfService
96
val IPTOS_LOWCOST: TypeOfService
97
val IPTOS_RELIABILITY: TypeOfService
98
val IPTOS_THROUGHPUT: TypeOfService
99
val IPTOS_LOWDELAY: TypeOfService
100
}
101
}
102
```
103
104
Inline value class for IP Type of Service (ToS) field configuration.
105
106
**Properties:**
107
- `value: UByte` - The underlying byte value for the ToS field
108
- `intValue: Int` - Computed property returning the ToS value as an integer
109
110
**Constructors:**
111
- `TypeOfService(value: UByte)` - Primary constructor taking a UByte value
112
- `TypeOfService(value: Int)` - Secondary constructor taking Int and converting to UByte
113
114
**Companion Constants:**
115
- `UNDEFINED` - Default/undefined ToS value
116
- `IPTOS_LOWCOST` - Optimize for low cost
117
- `IPTOS_RELIABILITY` - Optimize for reliability
118
- `IPTOS_THROUGHPUT` - Optimize for high throughput
119
- `IPTOS_LOWDELAY` - Optimize for low latency
120
121
## Usage Examples
122
123
### Basic Socket Lifecycle Management
124
125
```kotlin
126
import io.ktor.network.sockets.*
127
import io.ktor.network.selector.*
128
129
suspend fun monitorSocketLifecycle() {
130
val selectorManager = SelectorManager()
131
val socket = aSocket(selectorManager)
132
.tcp()
133
.connect(InetSocketAddress("example.com", 80))
134
135
println("Socket connected: ${!socket.isClosed}")
136
137
// Set up monitoring coroutine
138
launch {
139
socket.awaitClosed()
140
println("Socket has been closed")
141
}
142
143
// Use socket...
144
delay(1000)
145
146
// Close and verify
147
socket.close()
148
println("After close: isClosed = ${socket.isClosed}")
149
150
selectorManager.close()
151
}
152
```
153
154
### Using Connection Wrapper
155
156
```kotlin
157
suspend fun useConnectionWrapper() {
158
val selectorManager = SelectorManager()
159
val socket = aSocket(selectorManager)
160
.tcp()
161
.connect(InetSocketAddress("httpbin.org", 80))
162
163
// Create connection wrapper
164
val connection = socket.connection()
165
166
println("Connection established:")
167
println("Socket: ${connection.socket.remoteAddress}")
168
169
// Send HTTP request
170
connection.output.writeStringUtf8("GET /get HTTP/1.1\r\n")
171
connection.output.writeStringUtf8("Host: httpbin.org\r\n")
172
connection.output.writeStringUtf8("Connection: close\r\n\r\n")
173
connection.output.flush()
174
175
// Read response
176
val response = connection.input.readUTF8Line()
177
println("Response: $response")
178
179
// Connection.close() handles all cleanup
180
connection.close()
181
selectorManager.close()
182
}
183
```
184
185
### Server Socket Port Utilities
186
187
```kotlin
188
suspend fun serverPortUtilities() {
189
val selectorManager = SelectorManager()
190
191
// Server with dynamic port assignment
192
val server = aSocket(selectorManager)
193
.tcp()
194
.bind(InetSocketAddress("localhost", 0)) // Port 0 = any available
195
196
// Get the assigned port
197
val assignedPort = server.port
198
println("Server listening on port: $assignedPort")
199
println("Full address: ${server.localAddress}")
200
201
// Another way to get port from address
202
val addressPort = (server.localAddress as InetSocketAddress).port
203
println("Port from address: $addressPort")
204
205
server.close()
206
selectorManager.close()
207
}
208
```
209
210
### Advanced I/O Channel Usage
211
212
```kotlin
213
import io.ktor.utils.io.*
214
215
suspend fun advancedChannelUsage() {
216
val selectorManager = SelectorManager()
217
val socket = aSocket(selectorManager)
218
.tcp()
219
.connect(InetSocketAddress("example.com", 80))
220
221
// Open channels with specific settings
222
val input = socket.openReadChannel()
223
val output = socket.openWriteChannel(autoFlush = true) // Auto-flush enabled
224
225
// Send data
226
output.writeStringUtf8("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
227
228
// Read response headers
229
val headers = mutableListOf<String>()
230
while (true) {
231
val line = input.readUTF8Line() ?: break
232
if (line.isEmpty()) break // End of headers
233
headers.add(line)
234
}
235
236
println("Response headers:")
237
headers.forEach { println(it) }
238
239
socket.close()
240
selectorManager.close()
241
}
242
```
243
244
### Type of Service Configuration
245
246
```kotlin
247
// Note: ToS configuration would typically be applied during socket creation
248
// This example shows the ToS value usage pattern
249
250
fun demonstrateTypeOfService() {
251
// Different QoS requirements
252
val lowLatencyToS = TypeOfService.IPTOS_LOWDELAY
253
val highThroughputToS = TypeOfService.IPTOS_THROUGHPUT
254
val reliableToS = TypeOfService.IPTOS_RELIABILITY
255
val lowCostToS = TypeOfService.IPTOS_LOWCOST
256
257
println("ToS values:")
258
println("Low Latency: ${lowLatencyToS.intValue}")
259
println("High Throughput: ${highThroughputToS.intValue}")
260
println("Reliability: ${reliableToS.intValue}")
261
println("Low Cost: ${lowCostToS.intValue}")
262
263
// Custom ToS value
264
val customToS = TypeOfService(0x18) // Custom value
265
println("Custom ToS: ${customToS.intValue}")
266
}
267
```
268
269
### Error-Resilient Connection Management
270
271
```kotlin
272
suspend fun resilientConnectionManagement() {
273
val selectorManager = SelectorManager()
274
275
try {
276
val socket = aSocket(selectorManager)
277
.tcp()
278
.configure {
279
socketTimeout = 10000 // 10 second timeout
280
}
281
.connect(InetSocketAddress("example.com", 80))
282
283
// Monitor connection state
284
if (!socket.isClosed) {
285
val connection = socket.connection()
286
287
try {
288
// Perform operations
289
connection.output.writeStringUtf8("Hello\n")
290
connection.output.flush()
291
292
// Check if still connected before reading
293
if (!connection.socket.isClosed) {
294
val response = connection.input.readUTF8Line()
295
println("Received: $response")
296
}
297
298
} catch (e: Exception) {
299
println("Connection error: ${e.message}")
300
} finally {
301
connection.close()
302
}
303
}
304
305
} catch (e: Exception) {
306
println("Socket creation failed: ${e.message}")
307
} finally {
308
selectorManager.close()
309
}
310
}
311
```
312
313
### Bulk Connection Operations
314
315
```kotlin
316
suspend fun bulkConnectionOperations() {
317
val selectorManager = SelectorManager()
318
val connections = mutableListOf<Connection>()
319
320
try {
321
// Create multiple connections
322
val addresses = listOf(
323
InetSocketAddress("httpbin.org", 80),
324
InetSocketAddress("example.com", 80),
325
InetSocketAddress("google.com", 80)
326
)
327
328
addresses.forEach { address ->
329
try {
330
val socket = aSocket(selectorManager)
331
.tcp()
332
.connect(address)
333
334
val connection = socket.connection()
335
connections.add(connection)
336
337
println("Connected to ${address}")
338
} catch (e: Exception) {
339
println("Failed to connect to ${address}: ${e.message}")
340
}
341
}
342
343
// Perform operations on all connections
344
connections.forEach { connection ->
345
launch {
346
try {
347
connection.output.writeStringUtf8("GET / HTTP/1.1\r\nHost: ${(connection.socket.remoteAddress as InetSocketAddress).hostname}\r\n\r\n")
348
connection.output.flush()
349
350
val response = connection.input.readUTF8Line()
351
println("Response from ${connection.socket.remoteAddress}: $response")
352
} catch (e: Exception) {
353
println("Operation failed for ${connection.socket.remoteAddress}: ${e.message}")
354
}
355
}
356
}
357
358
// Wait for operations to complete
359
delay(5000)
360
361
} finally {
362
// Clean up all connections
363
connections.forEach { connection ->
364
try {
365
connection.close()
366
} catch (e: Exception) {
367
println("Error closing connection: ${e.message}")
368
}
369
}
370
selectorManager.close()
371
}
372
}
373
```
374
375
### Connection Pooling Utility
376
377
```kotlin
378
class ConnectionPool(private val selectorManager: SelectorManager) {
379
private val connections = mutableMapOf<SocketAddress, MutableList<Connection>>()
380
381
suspend fun getConnection(address: SocketAddress): Connection {
382
val pool = connections.getOrPut(address) { mutableListOf() }
383
384
return if (pool.isNotEmpty()) {
385
val connection = pool.removeAt(0)
386
if (!connection.socket.isClosed) {
387
connection
388
} else {
389
createNewConnection(address)
390
}
391
} else {
392
createNewConnection(address)
393
}
394
}
395
396
private suspend fun createNewConnection(address: SocketAddress): Connection {
397
val socket = aSocket(selectorManager)
398
.tcp()
399
.connect(address)
400
401
return socket.connection()
402
}
403
404
fun returnConnection(connection: Connection) {
405
if (!connection.socket.isClosed) {
406
val address = connection.socket.remoteAddress
407
val pool = connections.getOrPut(address) { mutableListOf() }
408
pool.add(connection)
409
} else {
410
connection.close()
411
}
412
}
413
414
fun closeAll() {
415
connections.values.flatten().forEach { connection ->
416
try {
417
connection.close()
418
} catch (e: Exception) {
419
println("Error closing pooled connection: ${e.message}")
420
}
421
}
422
connections.clear()
423
}
424
}
425
426
suspend fun useConnectionPool() {
427
val selectorManager = SelectorManager()
428
val pool = ConnectionPool(selectorManager)
429
430
try {
431
val address = InetSocketAddress("httpbin.org", 80)
432
433
// Get connection from pool
434
val connection1 = pool.getConnection(address)
435
println("Got connection: ${connection1.socket.remoteAddress}")
436
437
// Use connection...
438
connection1.output.writeStringUtf8("GET /get HTTP/1.1\r\nHost: httpbin.org\r\n\r\n")
439
440
// Return to pool for reuse
441
pool.returnConnection(connection1)
442
443
// Get another connection (might be the same one)
444
val connection2 = pool.getConnection(address)
445
println("Got connection: ${connection2.socket.remoteAddress}")
446
447
pool.returnConnection(connection2)
448
449
} finally {
450
pool.closeAll()
451
selectorManager.close()
452
}
453
}
454
```
455
456
## Constants and Limits
457
458
### Maximum Values
459
460
```kotlin { .api }
461
const val MAX_DATAGRAM_SIZE = 65535
462
```
463
464
Maximum size for UDP datagrams (65535 bytes).
465
466
## Type Definitions
467
468
### Required Import Statements
469
470
```kotlin
471
import io.ktor.network.sockets.*
472
import io.ktor.utils.io.*
473
import kotlinx.coroutines.*
474
```
475
476
### Related Types
477
478
- Extends all socket interfaces - See [Socket Interfaces](./socket-interfaces.md)
479
- Used with socket builders - See [Socket Builders](./socket-builders.md)
480
- Enhances datagram operations - See [Datagram Sockets](./datagram-sockets.md)
481
- Works with all address types - See [Address Types](./address-types.md)
482
- `ByteReadChannel`, `ByteWriteChannel` - From kotlinx-io
483
- `Closeable` - From Kotlin standard library
484
485
### Exception Types
486
487
Utility functions may throw the same exceptions as their underlying socket operations. Always handle exceptions appropriately in production code.