我在為 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調度程式呼叫時永遠不會回傳? - 我真的需要為這樣的生產者/消費者作業產生一個執行緒嗎?
- 你能展示如何以“協程友好”的方式很好地實作這么長的阻塞代碼嗎?
謝謝
uj5u.com熱心網友回復:
receiveMessages()是一個掛起函式,它呼叫另一個掛起函式withContext(),而后者又是一個無限回圈。因此,呼叫socket.receiveMessages(channel)將在回圈未完成時暫停代碼執行。您需要為消費者和生產者啟動單獨的協程,例如使用
launch函式。使用協程的一些示例:
val someScope = CoroutineScope(Dispatchers.Main) private suspend fun receiveLoop(socket: MySocketUDP) = someScope.launch { val channel = Channel<Message>(16) socket.receiveMessages(channel) Log.d("MODEL", "Entering msg loop") for (msg in channel) { dispatchRcvMessage(msg) } } // In MySocketUDP suspend fun receiveMessages(channel: SendChannel<Message>) { someAnotherScope.launch { // or can use coroutineScope builder function 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 } } } }
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/401107.html
上一篇:計算整數陣列值
