Ktor network utilities for macOS ARM64 target - provides asynchronous networking components including sockets, selectors, and connection utilities for building Kotlin multiplatform network applications
—
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.
val ASocket.isClosed: Boolean
suspend fun ASocket.awaitClosed()Extensions for monitoring socket lifecycle state.
Properties:
isClosed: Boolean - Returns true if the socket has been closedMethods:
suspend fun awaitClosed() - Suspends the current coroutine until the socket is closedfun AReadable.openReadChannel(): ByteReadChannel
fun AWritable.openWriteChannel(autoFlush: Boolean = false): ByteWriteChannelExtensions for opening I/O channels on readable and writable sockets.
AReadable Extensions:
openReadChannel(): ByteReadChannel - Opens a dedicated read channel for receiving dataAWritable Extensions:
openWriteChannel(autoFlush: Boolean = false): ByteWriteChannel - Opens a dedicated write channel for sending data
autoFlush: Boolean - Whether to automatically flush written data (default: false)fun Socket.connection(): ConnectionCreates a convenient Connection wrapper for TCP sockets.
Returns: Connection - A wrapper containing both input and output channels
val ServerSocket.port: IntExtension property to get the port number from a server socket.
Returns: Int - The port number the server socket is bound to
class Connection(
val socket: Socket,
val input: ByteReadChannel,
val output: ByteWriteChannel
) : Closeable {
override fun close()
}Convenience class that combines a socket with its I/O channels for easier handling.
Properties:
socket: Socket - The underlying TCP socketinput: ByteReadChannel - Read channel for receiving dataoutput: ByteWriteChannel - Write channel for sending dataMethods:
close() - Closes the connection and all associated resources@JvmInline
value class TypeOfService(val value: UByte) {
constructor(value: Int) : this(value.toUByte())
val intValue: Int get() = value.toInt()
companion object {
val UNDEFINED: TypeOfService
val IPTOS_LOWCOST: TypeOfService
val IPTOS_RELIABILITY: TypeOfService
val IPTOS_THROUGHPUT: TypeOfService
val IPTOS_LOWDELAY: TypeOfService
}
}Inline value class for IP Type of Service (ToS) field configuration.
Properties:
value: UByte - The underlying byte value for the ToS fieldintValue: Int - Computed property returning the ToS value as an integerConstructors:
TypeOfService(value: UByte) - Primary constructor taking a UByte valueTypeOfService(value: Int) - Secondary constructor taking Int and converting to UByteCompanion Constants:
UNDEFINED - Default/undefined ToS valueIPTOS_LOWCOST - Optimize for low costIPTOS_RELIABILITY - Optimize for reliabilityIPTOS_THROUGHPUT - Optimize for high throughputIPTOS_LOWDELAY - Optimize for low latencyimport io.ktor.network.sockets.*
import io.ktor.network.selector.*
suspend fun monitorSocketLifecycle() {
val selectorManager = SelectorManager()
val socket = aSocket(selectorManager)
.tcp()
.connect(InetSocketAddress("example.com", 80))
println("Socket connected: ${!socket.isClosed}")
// Set up monitoring coroutine
launch {
socket.awaitClosed()
println("Socket has been closed")
}
// Use socket...
delay(1000)
// Close and verify
socket.close()
println("After close: isClosed = ${socket.isClosed}")
selectorManager.close()
}suspend fun useConnectionWrapper() {
val selectorManager = SelectorManager()
val socket = aSocket(selectorManager)
.tcp()
.connect(InetSocketAddress("httpbin.org", 80))
// Create connection wrapper
val connection = socket.connection()
println("Connection established:")
println("Socket: ${connection.socket.remoteAddress}")
// Send HTTP request
connection.output.writeStringUtf8("GET /get HTTP/1.1\r\n")
connection.output.writeStringUtf8("Host: httpbin.org\r\n")
connection.output.writeStringUtf8("Connection: close\r\n\r\n")
connection.output.flush()
// Read response
val response = connection.input.readUTF8Line()
println("Response: $response")
// Connection.close() handles all cleanup
connection.close()
selectorManager.close()
}suspend fun serverPortUtilities() {
val selectorManager = SelectorManager()
// Server with dynamic port assignment
val server = aSocket(selectorManager)
.tcp()
.bind(InetSocketAddress("localhost", 0)) // Port 0 = any available
// Get the assigned port
val assignedPort = server.port
println("Server listening on port: $assignedPort")
println("Full address: ${server.localAddress}")
// Another way to get port from address
val addressPort = (server.localAddress as InetSocketAddress).port
println("Port from address: $addressPort")
server.close()
selectorManager.close()
}import io.ktor.utils.io.*
suspend fun advancedChannelUsage() {
val selectorManager = SelectorManager()
val socket = aSocket(selectorManager)
.tcp()
.connect(InetSocketAddress("example.com", 80))
// Open channels with specific settings
val input = socket.openReadChannel()
val output = socket.openWriteChannel(autoFlush = true) // Auto-flush enabled
// Send data
output.writeStringUtf8("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
// Read response headers
val headers = mutableListOf<String>()
while (true) {
val line = input.readUTF8Line() ?: break
if (line.isEmpty()) break // End of headers
headers.add(line)
}
println("Response headers:")
headers.forEach { println(it) }
socket.close()
selectorManager.close()
}// Note: ToS configuration would typically be applied during socket creation
// This example shows the ToS value usage pattern
fun demonstrateTypeOfService() {
// Different QoS requirements
val lowLatencyToS = TypeOfService.IPTOS_LOWDELAY
val highThroughputToS = TypeOfService.IPTOS_THROUGHPUT
val reliableToS = TypeOfService.IPTOS_RELIABILITY
val lowCostToS = TypeOfService.IPTOS_LOWCOST
println("ToS values:")
println("Low Latency: ${lowLatencyToS.intValue}")
println("High Throughput: ${highThroughputToS.intValue}")
println("Reliability: ${reliableToS.intValue}")
println("Low Cost: ${lowCostToS.intValue}")
// Custom ToS value
val customToS = TypeOfService(0x18) // Custom value
println("Custom ToS: ${customToS.intValue}")
}suspend fun resilientConnectionManagement() {
val selectorManager = SelectorManager()
try {
val socket = aSocket(selectorManager)
.tcp()
.configure {
socketTimeout = 10000 // 10 second timeout
}
.connect(InetSocketAddress("example.com", 80))
// Monitor connection state
if (!socket.isClosed) {
val connection = socket.connection()
try {
// Perform operations
connection.output.writeStringUtf8("Hello\n")
connection.output.flush()
// Check if still connected before reading
if (!connection.socket.isClosed) {
val response = connection.input.readUTF8Line()
println("Received: $response")
}
} catch (e: Exception) {
println("Connection error: ${e.message}")
} finally {
connection.close()
}
}
} catch (e: Exception) {
println("Socket creation failed: ${e.message}")
} finally {
selectorManager.close()
}
}suspend fun bulkConnectionOperations() {
val selectorManager = SelectorManager()
val connections = mutableListOf<Connection>()
try {
// Create multiple connections
val addresses = listOf(
InetSocketAddress("httpbin.org", 80),
InetSocketAddress("example.com", 80),
InetSocketAddress("google.com", 80)
)
addresses.forEach { address ->
try {
val socket = aSocket(selectorManager)
.tcp()
.connect(address)
val connection = socket.connection()
connections.add(connection)
println("Connected to ${address}")
} catch (e: Exception) {
println("Failed to connect to ${address}: ${e.message}")
}
}
// Perform operations on all connections
connections.forEach { connection ->
launch {
try {
connection.output.writeStringUtf8("GET / HTTP/1.1\r\nHost: ${(connection.socket.remoteAddress as InetSocketAddress).hostname}\r\n\r\n")
connection.output.flush()
val response = connection.input.readUTF8Line()
println("Response from ${connection.socket.remoteAddress}: $response")
} catch (e: Exception) {
println("Operation failed for ${connection.socket.remoteAddress}: ${e.message}")
}
}
}
// Wait for operations to complete
delay(5000)
} finally {
// Clean up all connections
connections.forEach { connection ->
try {
connection.close()
} catch (e: Exception) {
println("Error closing connection: ${e.message}")
}
}
selectorManager.close()
}
}class ConnectionPool(private val selectorManager: SelectorManager) {
private val connections = mutableMapOf<SocketAddress, MutableList<Connection>>()
suspend fun getConnection(address: SocketAddress): Connection {
val pool = connections.getOrPut(address) { mutableListOf() }
return if (pool.isNotEmpty()) {
val connection = pool.removeAt(0)
if (!connection.socket.isClosed) {
connection
} else {
createNewConnection(address)
}
} else {
createNewConnection(address)
}
}
private suspend fun createNewConnection(address: SocketAddress): Connection {
val socket = aSocket(selectorManager)
.tcp()
.connect(address)
return socket.connection()
}
fun returnConnection(connection: Connection) {
if (!connection.socket.isClosed) {
val address = connection.socket.remoteAddress
val pool = connections.getOrPut(address) { mutableListOf() }
pool.add(connection)
} else {
connection.close()
}
}
fun closeAll() {
connections.values.flatten().forEach { connection ->
try {
connection.close()
} catch (e: Exception) {
println("Error closing pooled connection: ${e.message}")
}
}
connections.clear()
}
}
suspend fun useConnectionPool() {
val selectorManager = SelectorManager()
val pool = ConnectionPool(selectorManager)
try {
val address = InetSocketAddress("httpbin.org", 80)
// Get connection from pool
val connection1 = pool.getConnection(address)
println("Got connection: ${connection1.socket.remoteAddress}")
// Use connection...
connection1.output.writeStringUtf8("GET /get HTTP/1.1\r\nHost: httpbin.org\r\n\r\n")
// Return to pool for reuse
pool.returnConnection(connection1)
// Get another connection (might be the same one)
val connection2 = pool.getConnection(address)
println("Got connection: ${connection2.socket.remoteAddress}")
pool.returnConnection(connection2)
} finally {
pool.closeAll()
selectorManager.close()
}
}const val MAX_DATAGRAM_SIZE = 65535Maximum size for UDP datagrams (65535 bytes).
import io.ktor.network.sockets.*
import io.ktor.utils.io.*
import kotlinx.coroutines.*ByteReadChannel, ByteWriteChannel - From kotlinx-ioCloseable - From Kotlin standard libraryUtility functions may throw the same exceptions as their underlying socket operations. Always handle exceptions appropriately in production code.
Install with Tessl CLI
npx tessl i tessl/maven-io-ktor--ktor-network-macosarm64