使用 Ktor HttpClient(CIO) websocket 发送内容时如何捕获 Broken pipe 异常?

How to catch Broken pipe exception when send something using Ktor HttpClient(CIO) websocket?

我在 Android 8

中使用 Ktor 1.2.5 和 Kotlin 1.3.61 开发网络应用程序

当 netty websocket 服务器像最近的应用清理一样不正常地关闭时,websocket 客户端不会收到任何事件。 那时,如果 websocket 客户端向服务器发送内容,则 App 在发生 Broken pope 异常后崩溃。 但是,这个 Broken pipe 异常不会在发送时捕获。 在哪里捕获 Broken pipe 异常?

这是异常日志

E/AndroidRuntime: FATAL EXCEPTION: Thread-6
    Process: com.example.chatkt1, PID: 805
    java.io.IOException: Broken pipe
        at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
        at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:55)
        at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
        at sun.nio.ch.IOUtil.write(IOUtil.java:51)
        at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:512)
        at io.ktor.network.sockets.CIOWriterKt$attachForWritingDirectImpl.invokeSuspend(CIOWriter.kt:75)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedContinuation.resumeWith(Dispatched.kt:108)
        at kotlinx.coroutines.io.internal.CancellableReusableContinuation.resumeWith(CancellableReusableContinuation.kt:93)
        at kotlinx.coroutines.io.ByteBufferChannel.resumeReadOp(ByteBufferChannel.kt:2211)
        at kotlinx.coroutines.io.ByteBufferChannel.flushImpl(ByteBufferChannel.kt:156)
        at kotlinx.coroutines.io.ByteBufferChannel.flush(ByteBufferChannel.kt:162)
        at io.ktor.http.cio.websocket.WebSocketWriter.drainQueueAndSerialize(WebSocketWriter.kt:108)
        at io.ktor.http.cio.websocket.WebSocketWriter.writeLoop(WebSocketWriter.kt:47)
        at io.ktor.http.cio.websocket.WebSocketWriter$writeLoop.invokeSuspend(Unknown Source:12)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764) 

这里是websocket客户端代码

fun sendToServer(message: String) {
    if(session != null) {
        CoroutineScope(Dispatchers.IO).launch {
            mutex.withLock {
                try {
                    session!!.send(message)
                    session!!.flush()
                } catch (e: IOException) {              
                    if (e.message.equals("Broken pipe")) {
                        println("catch Broken pipe exception")
                    }
                }
            }
        }
    }
}

我通过参考 Aleksei Tirman 的评论解决了问题。

 val old = Thread.setDefaultUncaughtExceptionHandler { _, e ->
        if (e is java.io.IOException && e.message.equals("Broken pipe")) {
            println("catch Broken pipe exception")
        } else {
            android.os.Process.killProcess(android.os.Process.myPid())
            exitProcess(10);
        }
    }

效果很好。