or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdio-operations.mdselector-management.mdsocket-addresses.mdsocket-configuration.mdsocket-creation.mdtcp-operations.mdudp-operations.md

io-operations.mddocs/

0

# I/O Operations

1

2

Socket I/O operations using ByteChannel integration for reading and writing data with support for both stream-based and packet-based communication.

3

4

## Capabilities

5

6

### Read/Write Socket Interface

7

8

Combined interface for sockets that support both reading and writing operations.

9

10

```kotlin { .api }

11

/**

12

* Represents both readable and writable socket

13

*/

14

interface ReadWriteSocket : ASocket, AReadable, AWritable

15

```

16

17

### Readable Socket Operations

18

19

Interface and operations for reading data from sockets.

20

21

```kotlin { .api }

22

/**

23

* Represents a readable socket

24

*/

25

interface AReadable {

26

/**

27

* Attach channel for reading so incoming bytes appears in the attached channel.

28

* Only one channel could be attached

29

* @param channel ByteChannel to attach for reading

30

* @returns a job that does supply data

31

*/

32

fun attachForReading(channel: ByteChannel): WriterJob

33

}

34

35

/**

36

* Open a read channel, could be done only once

37

* @returns ByteReadChannel for reading data from the socket

38

*/

39

fun AReadable.openReadChannel(): ByteReadChannel

40

```

41

42

**Usage Example:**

43

44

```kotlin

45

import io.ktor.network.sockets.*

46

import io.ktor.network.selector.*

47

import io.ktor.utils.io.*

48

49

val selectorManager = SelectorManager()

50

val socket = aSocket(selectorManager).tcp().connect("localhost", 8080)

51

52

// Method 1: Open read channel directly

53

val readChannel = socket.openReadChannel()

54

val line = readChannel.readUTF8Line()

55

println("Received: $line")

56

57

// Method 2: Attach custom channel for reading

58

val customChannel = ByteChannel()

59

val readerJob = socket.attachForReading(customChannel)

60

61

// Read from custom channel

62

launch {

63

val data = customChannel.readUTF8Line()

64

println("Custom channel received: $data")

65

}

66

67

// Clean up

68

readerJob.cancel()

69

socket.close()

70

```

71

72

### Writable Socket Operations

73

74

Interface and operations for writing data to sockets.

75

76

```kotlin { .api }

77

/**

78

* Represents a writable socket

79

*/

80

interface AWritable {

81

/**

82

* Attach channel for writing so bytes written to the attached channel will be transmitted.

83

* Only one channel could be attached

84

* @param channel ByteChannel to attach for writing

85

* @returns a job that does transmit data from the channel

86

*/

87

fun attachForWriting(channel: ByteChannel): ReaderJob

88

}

89

90

/**

91

* Open a write channel, could be opened only once

92

* @param autoFlush whether returned channel do flush for every write operation

93

* @returns ByteWriteChannel for writing data to the socket

94

*/

95

fun AWritable.openWriteChannel(autoFlush: Boolean = false): ByteWriteChannel

96

```

97

98

**Usage Example:**

99

100

```kotlin

101

import io.ktor.network.sockets.*

102

import io.ktor.network.selector.*

103

import io.ktor.utils.io.*

104

105

val selectorManager = SelectorManager()

106

val socket = aSocket(selectorManager).tcp().connect("localhost", 8080)

107

108

// Method 1: Open write channel directly

109

val writeChannel = socket.openWriteChannel(autoFlush = true)

110

writeChannel.writeStringUtf8("Hello, Server!")

111

// autoFlush = true means data is sent immediately

112

113

// Method 2: Manual flush control

114

val manualWriteChannel = socket.openWriteChannel(autoFlush = false)

115

manualWriteChannel.writeStringUtf8("Message 1\n")

116

manualWriteChannel.writeStringUtf8("Message 2\n")

117

manualWriteChannel.flush() // Send both messages at once

118

119

// Method 3: Attach custom channel for writing

120

val customChannel = ByteChannel()

121

val writerJob = socket.attachForWriting(customChannel)

122

123

// Write to custom channel

124

launch {

125

customChannel.writeStringUtf8("Custom channel message")

126

customChannel.flush()

127

}

128

129

// Clean up

130

writerJob.cancel()

131

socket.close()

132

```

133

134

### Connection Wrapper

135

136

Convenience class that combines a socket with its I/O channels for easier management.

137

138

```kotlin { .api }

139

/**

140

* Represents a connected socket with its input and output

141

*/

142

class Connection(

143

val socket: Socket,

144

val input: ByteReadChannel,

145

val output: ByteWriteChannel

146

)

147

148

/**

149

* Opens socket input and output channels and returns connection object

150

* @returns Connection object with socket and I/O channels

151

*/

152

fun Socket.connection(): Connection

153

```

154

155

**Usage Examples:**

156

157

```kotlin

158

import io.ktor.network.sockets.*

159

import io.ktor.network.selector.*

160

import io.ktor.utils.io.*

161

import kotlinx.coroutines.*

162

163

val selectorManager = SelectorManager()

164

165

// Simple client using Connection

166

suspend fun simpleClient() {

167

val socket = aSocket(selectorManager).tcp().connect("localhost", 8080)

168

val connection = socket.connection()

169

170

// Send request

171

connection.output.writeStringUtf8("GET /api/data HTTP/1.1\r\nHost: localhost\r\n\r\n")

172

connection.output.flush()

173

174

// Read response

175

val statusLine = connection.input.readUTF8Line()

176

println("Response: $statusLine")

177

178

// Read remaining headers

179

while (true) {

180

val header = connection.input.readUTF8Line()

181

if (header.isNullOrEmpty()) break

182

println("Header: $header")

183

}

184

185

connection.socket.close()

186

}

187

188

// Echo server using Connection

189

suspend fun echoServer() {

190

val serverSocket = aSocket(selectorManager).tcp().bind("localhost", 8080)

191

192

while (true) {

193

val clientSocket = serverSocket.accept()

194

launch {

195

val connection = clientSocket.connection()

196

197

try {

198

while (true) {

199

val line = connection.input.readUTF8Line() ?: break

200

connection.output.writeStringUtf8("Echo: $line\n")

201

connection.output.flush()

202

}

203

} finally {

204

connection.socket.close()

205

}

206

}

207

}

208

}

209

210

// Bidirectional communication

211

suspend fun chatClient() {

212

val socket = aSocket(selectorManager).tcp().connect("chat-server.com", 8080)

213

val connection = socket.connection()

214

215

// Send messages

216

launch {

217

while (true) {

218

val message = readLine() ?: break

219

connection.output.writeStringUtf8("$message\n")

220

connection.output.flush()

221

}

222

}

223

224

// Receive messages

225

launch {

226

while (true) {

227

val message = connection.input.readUTF8Line() ?: break

228

println("Received: $message")

229

}

230

}

231

232

// Keep connection alive

233

connection.socket.awaitClosed()

234

}

235

```

236

237

### Advanced I/O Patterns

238

239

Advanced patterns for handling complex I/O scenarios.

240

241

**Binary Data Handling:**

242

243

```kotlin

244

import io.ktor.network.sockets.*

245

import io.ktor.network.selector.*

246

import io.ktor.utils.io.*

247

import io.ktor.utils.io.core.*

248

249

suspend fun binaryDataExample() {

250

val selectorManager = SelectorManager()

251

val socket = aSocket(selectorManager).tcp().connect("localhost", 8080)

252

val connection = socket.connection()

253

254

// Send binary data

255

connection.output.writeByte(0x01)

256

connection.output.writeInt(12345)

257

connection.output.writeFloat(3.14f)

258

connection.output.flush()

259

260

// Read binary data

261

val flag = connection.input.readByte()

262

val number = connection.input.readInt()

263

val pi = connection.input.readFloat()

264

265

println("Received: flag=$flag, number=$number, pi=$pi")

266

267

connection.socket.close()

268

selectorManager.close()

269

}

270

```

271

272

**Packet-based Communication:**

273

274

```kotlin

275

import io.ktor.network.sockets.*

276

import io.ktor.network.selector.*

277

import io.ktor.utils.io.*

278

import io.ktor.utils.io.core.*

279

280

suspend fun packetBasedExample() {

281

val selectorManager = SelectorManager()

282

val socket = aSocket(selectorManager).tcp().connect("localhost", 8080)

283

val connection = socket.connection()

284

285

// Send packet with length prefix

286

val message = "Hello, World!"

287

val messageBytes = message.toByteArray()

288

289

connection.output.writeInt(messageBytes.size) // Length prefix

290

connection.output.writeFully(messageBytes) // Message data

291

connection.output.flush()

292

293

// Read packet with length prefix

294

val length = connection.input.readInt()

295

val buffer = ByteArray(length)

296

connection.input.readFully(buffer)

297

val receivedMessage = buffer.decodeToString()

298

299

println("Received packet: $receivedMessage")

300

301

connection.socket.close()

302

selectorManager.close()

303

}

304

```

305

306

**Streaming Large Data:**

307

308

```kotlin

309

import io.ktor.network.sockets.*

310

import io.ktor.network.selector.*

311

import io.ktor.utils.io.*

312

import kotlinx.coroutines.*

313

import java.io.File

314

315

suspend fun streamingExample() {

316

val selectorManager = SelectorManager()

317

val socket = aSocket(selectorManager).tcp().connect("localhost", 8080)

318

val connection = socket.connection()

319

320

// Stream file upload

321

launch {

322

val file = File("large-file.dat")

323

val buffer = ByteArray(8192) // 8KB buffer

324

325

file.inputStream().use { fileInput ->

326

while (true) {

327

val bytesRead = fileInput.read(buffer)

328

if (bytesRead == -1) break

329

330

connection.output.writeFully(buffer, 0, bytesRead)

331

connection.output.flush()

332

}

333

}

334

335

connection.output.close() // Signal end of stream

336

}

337

338

// Stream file download

339

launch {

340

val outputFile = File("downloaded-file.dat")

341

val buffer = ByteArray(8192)

342

343

outputFile.outputStream().use { fileOutput ->

344

while (true) {

345

val bytesAvailable = connection.input.readAvailable(buffer)

346

if (bytesAvailable == -1) break

347

348

fileOutput.write(buffer, 0, bytesAvailable)

349

}

350

}

351

}

352

353

connection.socket.awaitClosed()

354

selectorManager.close()

355

}

356

```

357

358

**Error Handling:**

359

360

```kotlin

361

import io.ktor.network.sockets.*

362

import io.ktor.network.selector.*

363

import io.ktor.utils.io.*

364

import kotlinx.coroutines.*

365

366

suspend fun errorHandlingExample() {

367

val selectorManager = SelectorManager()

368

369

try {

370

val socket = aSocket(selectorManager).tcp().connect("localhost", 8080) {

371

socketTimeout = 10000 // 10 second timeout

372

}

373

374

val connection = socket.connection()

375

376

// Wrap I/O operations in try-catch

377

try {

378

withTimeout(5000) { // 5 second operation timeout

379

connection.output.writeStringUtf8("Hello")

380

connection.output.flush()

381

382

val response = connection.input.readUTF8Line()

383

println("Response: $response")

384

}

385

} catch (e: SocketTimeoutException) {

386

println("Socket timeout: ${e.message}")

387

} catch (e: TimeoutCancellationException) {

388

println("Operation timeout: ${e.message}")

389

} catch (e: Exception) {

390

println("I/O error: ${e.message}")

391

} finally {

392

connection.socket.close()

393

}

394

395

} catch (e: ConnectException) {

396

println("Connection failed: ${e.message}")

397

} finally {

398

selectorManager.close()

399

}

400

}

401

```