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

Posted

技术标签:

【中文标题】使用 Ktor HttpClient(CIO) websocket 发送内容时如何捕获 Broken pipe 异常?【英文标题】:How to catch Broken pipe exception when send something using Ktor HttpClient(CIO) websocket? 【发布时间】:2021-06-12 14:48:23 【问题描述】:

我正在 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$1$1.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$1.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")
                    
                
            
        
    

【问题讨论】:

作为一种解决方法,您可以为所有线程设置一个异常处理程序docs.oracle.com/javase/7/docs/api/java/lang/…。 【参考方案1】:

我通过引用 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);
        
    

效果很好。

【讨论】:

以上是关于使用 Ktor HttpClient(CIO) websocket 发送内容时如何捕获 Broken pipe 异常?的主要内容,如果未能解决你的问题,请参考以下文章

Ktor 的 HttpClient 使用的正确模式

如何在 Multiplatform Ktor 和 Coil 之间共享 HttpClient?

Ktor HttpClient 在 runBlocking 中挂起

如何使用针对 linuxX64 的 ktor-client-core 修复“未解决的参考:HttpClient”

在 Kotlin 多平台项目中使用 Ktor HttpClient 将文件作为二进制文件

处理 HttpClient Ktor 中的异常