Как отметил Марко, ваш код все равно будет блокировать поток, даже если эта операция блокировки выполняется в асинхронной сопрограмме.Чтобы по-настоящему получить желаемое асинхронное поведение с Java и Kotlin, вам нужно использовать асинхронную версию Socket Channel
. Таким образом, вы получаете истинную асинхронную обработку сокетов.С помощью этого класса и метода suspendCoroutine Kotlin'а вы можете превратить асинхронные обработчики в приостанавливаемые вызовы.
Вот пример реализации его для чтения:
class TcpSocket(private val socket: AsynchronousSocketChannel) {
suspend fun read(buffer: ByteBuffer): Int {
return socket.asyncRead(buffer)
}
fun close() {
socket.close()
}
private suspend fun AsynchronousSocketChannel.asyncRead(buffer: ByteBuffer): Int {
return suspendCoroutine { continuation ->
this.read(buffer, continuation, ReadCompletionHandler)
}
}
object ReadCompletionHandler : CompletionHandler<Int, Continuation<Int>> {
override fun completed(result: Int, attachment: Continuation<Int>) {
attachment.resume(result)
}
override fun failed(exc: Throwable, attachment: Continuation<Int>) {
attachment.resumeWithException(exc)
}
}
}
Вы можете удалить обертку, которую я здесь делаю, и просто выставить метод asyncRead
в AsynchronousSocketChannel следующим образом:
suspend fun AsynchronousSocketChannel.asyncRead(buffer: ByteBuffer): Int {
return suspendCoroutine { continuation ->
this.read(buffer, continuation, ReadCompletionHandler)
}
}
object ReadCompletionHandler : CompletionHandler<Int, Continuation<Int>> {
override fun completed(result: Int, attachment: Continuation<Int>) {
attachment.resume(result)
}
override fun failed(exc: Throwable, attachment: Continuation<Int>) {
attachment.resumeWithException(exc)
}
}
Это все дело вкуса и каковы именно ваши цели дизайна.Вы должны иметь возможность реализовать аналогичный метод для начального соединения, как я сделал здесь для чтения.