async socket closing logic

This commit is contained in:
Sergey Chernov 2023-11-14 02:50:42 +03:00
parent 1814572a04
commit 75e91f8092
3 changed files with 93 additions and 73 deletions

View File

@ -24,6 +24,7 @@ actual fun acceptTcpDevice(port: Int): Flow<Transport.Device> {
it.bind(InetSocketAddress(InetAddress.getLocalHost(), port)) it.bind(InetSocketAddress(InetAddress.getLocalHost(), port))
} }
} }
while (true) {
println("Server socket ready $socket") println("Server socket ready $socket")
val connectedSocket = suspendCancellableCoroutine { continuation -> val connectedSocket = suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation { continuation.invokeOnCancellation {
@ -34,6 +35,7 @@ actual fun acceptTcpDevice(port: Int): Flow<Transport.Device> {
println("incoming connection") println("incoming connection")
emit(asyncSocketToDevice(connectedSocket)) emit(asyncSocketToDevice(connectedSocket))
} }
}
} }
actual suspend fun connectTcpDevice(address: NetworkAddress): Transport.Device { actual suspend fun connectTcpDevice(address: NetworkAddress): Transport.Device {

View File

@ -1,12 +1,9 @@
package net.sergeych.kiloparsec.adapter package net.sergeych.kiloparsec.adapter
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.*
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.ClosedReceiveChannelException import kotlinx.coroutines.channels.ClosedReceiveChannelException
import kotlinx.coroutines.channels.ClosedSendChannelException import kotlinx.coroutines.channels.ClosedSendChannelException
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import net.sergeych.crypto.encodeVarUnsigned import net.sergeych.crypto.encodeVarUnsigned
import net.sergeych.crypto.readVarUnsigned import net.sergeych.crypto.readVarUnsigned
import net.sergeych.crypto.toDump import net.sergeych.crypto.toDump
@ -28,11 +25,12 @@ suspend fun asyncSocketToDevice(socket: AsynchronousSocketChannel): Transport.De
globalLaunch { globalLaunch {
fun stop() { fun stop() {
cancel() cancel()
runCatching { socket.close() }
} }
val input = Channel<UByte>(1024) val input = Channel<UByte>(1024)
val output = Channel<UByte>(1024) val output = Channel<UByte>(1024)
// copy from socket to input // copy from socket to input
coroutineScope {
launch { launch {
val inb = ByteBuffer.allocate(1024) val inb = ByteBuffer.allocate(1024)
while (isActive) { while (isActive) {
@ -41,7 +39,7 @@ suspend fun asyncSocketToDevice(socket: AsynchronousSocketChannel): Transport.De
} }
println("--------- read chunk $size") println("--------- read chunk $size")
if (size < 0) stop() if (size < 0) stop()
else for (i in 0..<size) input.send(inb[i].toUByte().also { print(it.toInt().toChar())}) else for (i in 0..<size) input.send(inb[i].toUByte().also { print(it.toInt().toChar()) })
} }
} }
// copy from output tp socket // copy from output tp socket
@ -101,5 +99,7 @@ suspend fun asyncSocketToDevice(socket: AsynchronousSocketChannel): Transport.De
ProxyDevice(inputBlocks, outputBlocks) { stop() } ProxyDevice(inputBlocks, outputBlocks) { stop() }
) )
} }
globalLaunch { socket.close() }
}
return deferredDevice.await() return deferredDevice.await()
} }

View File

@ -2,7 +2,9 @@ package net.sergeych.kiloparsec.adapters
import com.ionspin.kotlin.crypto.util.decodeFromUByteArray import com.ionspin.kotlin.crypto.util.decodeFromUByteArray
import com.ionspin.kotlin.crypto.util.encodeToUByteArray import com.ionspin.kotlin.crypto.util.encodeToUByteArray
import kotlinx.coroutines.cancel
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.cancellable
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.yield import kotlinx.coroutines.yield
@ -36,24 +38,40 @@ class NetworkTest {
Log.connectConsole(Log.Level.DEBUG) Log.connectConsole(Log.Level.DEBUG)
coroutineScope { coroutineScope {
val serverFlow = acceptTcpDevice(17171) val serverFlow = acceptTcpDevice(17171).cancellable()
launch { launch {
serverFlow.collect { device -> serverFlow.collect { device ->
println("collected input: $device") println("collected input: $device")
device.output.send("Hello, world!".encodeToUByteArray()) device.output.send("Hello, world!".encodeToUByteArray())
device.output.send("Great".encodeToUByteArray()) device.output.send("Great".encodeToUByteArray())
while(true) { while(true) {
val x = device.input.receive()!!.decodeFromUByteArray() val x = device.input.receive()?.decodeFromUByteArray() ?: break
println("!****************** $x")
if( x== "Goodbye" ) break if( x== "Goodbye" ) break
if( x == "die") {
println("request death")
cancel()
break
}
println("ignoring unexpected input: $x") println("ignoring unexpected input: $x")
} }
} }
} }
yield() yield()
val s = connectTcpDevice("127.0.1.1:17171".toNetworkAddress()) var s = connectTcpDevice("127.0.1.1:17171".toNetworkAddress())
assertEquals("Hello, world!", s.input.receive()!!.decodeFromUByteArray()) assertEquals("Hello, world!", s.input.receive()!!.decodeFromUByteArray())
assertEquals("Great", s.input.receive()!!.decodeFromUByteArray()) assertEquals("Great", s.input.receive()!!.decodeFromUByteArray())
s.output.send("Goodbye".encodeToUByteArray()) s.output.send("Goodbye".encodeToUByteArray())
s.close()
println("connecting- -----------------------------------------------------------------")
s = connectTcpDevice("127.0.1.1:17171".toNetworkAddress())
assertEquals("Hello, world!", s.input.receive()!!.decodeFromUByteArray())
println("--1")
assertEquals("Great", s.input.receive()!!.decodeFromUByteArray())
println("--2")
s.output.send("die".encodeToUByteArray())
// s.close()
} }
} }
} }