【发布时间】:2022-01-02 11:42:17
【问题描述】:
我在为 Android 编写 UDP 消息接收循环时遇到了困难。
在下面的代码中,在receiveLoop 中,对receiveMessages 的调用永远不会返回,因此我永远不会进入消息处理循环。
请注意,我仍然可以接收数据包,但是当通道缓冲区已满时它会停止。
我希望receiveMessages 立即返回,而其中的阻塞 IO 循环仍将永远运行。
class MySocketUDP(private val params: SocketParams) {
private val rcvSocket: DatagramSocket by lazy {
val sock = DatagramSocket(params.rcvPort)
sock.reuseAddress = true
sock.soTimeout = 1000
sock
}
suspend fun receiveMessages(channel: SendChannel<Message>) {
withContext(Dispatchers.IO) {
val buf = ByteArray(MAX_MSG_SIZE)
while (true) {
val pkt = DatagramPacket(buf, buf.size)
try {
if (channel.isClosedForSend) {
break
}
rcvSocket.receive(pkt)
val msg = packetToMessage(buf, 0, pkt.length)
Log.d("SOCKET", "filling channel with $msg")
channel.send(msg)
} catch (ex: SocketTimeoutException) {
} catch (ex: CancellationException) {
break
}
}
}
}
}
class MyModel {
private suspend fun receiveLoop(socket: MySocketUDP) {
withContext(Dispatchers.Main) {
val channel = Channel<Message>(16)
socket.receiveMessages(channel)
Log.d("MODEL", "Entering msg loop")
for (msg in channel) {
dispatchRcvMessage(msg)
}
}
}
}
- 为什么
receiveMessages在IO调度程序中运行并从Main调度程序调用时从不返回? - 我是否需要为此类生产者/消费者工作实际生成一个线程?
- 您能否展示如何以“协程友好”的方式很好地实现如此长的阻塞代码?
谢谢
【问题讨论】:
-
为什么你期望
receiveMessages不等待循环结束就返回?挂起函数是同步的,因此它们与任何其他函数一样,仅在完成执行其主体时才返回。广告。 2:是和不是。你需要生成一个新的协程,而不是线程。 -
@broot 我误解了
withContext的作用。我认为如果新上下文与调用上下文不同,它必然会创建一个异步调用。
标签: android kotlin kotlin-coroutines blocking coroutinescope