Как получить асинхронный SNMPv2 в SCALA с помощью snmp4j

Я запрашиваю SNMP и хочу выполнить обратный вызов после завершения извлечения данных. Для этого я использую следующий код:

 def treeWalk(rootOid: String)(callback: (Seq[Tuple2[OID, Variable]]) => Unit) {//{{{
    val transport = new DefaultUdpTransportMapping
    val snmp = new Snmp(transport)
    transport.listen

    val target = new CommunityTarget
    target.setCommunity(new OctetString(community))
    target.setAddress(GenericAddress.parse("udp:" + address + "/161"))
    target.setRetries(retries)
    target.setTimeout(timeout)
    target.setVersion(SnmpConstants.version2c)

    val treeUtil = new TreeUtils(snmp, new DefaultPDUFactory)
    var variables: Seq[VariableBinding] = List()
    var _isFinished = false

    val listener = new TreeListener {
        def next(event: TreeEvent) = {
            println("NEXT")
            val vars = event.getVariableBindings
            if(vars != null)
               variables ++= vars
            true
        }
        def isFinished() = _isFinished
        def finished(event: TreeEvent) {
            val vars = event.getVariableBindings
            println("DONE")
            if(vars != null)
              variables ++= vars
            _isFinished = true
            snmp.close
            callback(variables.map(v => (v.getOid, v.getVariable)))
        }
  }
  treeUtil.walk(target, Array(new OID(rootOid)), null, listener)
}

Я не получаю ошибок или исключений, однако я никогда не вижу строк печати в next () и finished (), а также обратный вызов не выполняется. Что я делаю не так, как мне подключить к нему прослушиватель событий?

PS: Однострочная синхронная версия просто отлично возвращает данные ...

Я использую Scala 2.11.6 и SNMP4J 2.3


person Todor Markov    schedule 18.03.2015    source источник
comment
Я не знаком с SNMP, но если он похож на большинство обратных вызовов, которые я видел, то где вы ждете, чтобы дать время завершения вызова, чтобы обратный вызов мог быть выполнен?   -  person childofsoong    schedule 18.03.2015
comment
Я вызываю метод, который вы видите здесь, с println в качестве функции обратного вызова. Насколько я понимаю, обратный вызов должен быть следующей записью в стеке вызовов после метода. Таким образом, это будет означать, что ожидания не требуется, метод вызовет его по завершении. Верный?   -  person Todor Markov    schedule 18.03.2015
comment
В ситуации блокировки да. Однако, если у вас есть асинхронный вызов с обратным вызовом, программа может завершиться до завершения асинхронной операции. Вы можете сделать это, либо переведя его в спящий режим, либо перестроив свою программу, как показано в stackoverflow.com/questions/16256279/wait-for-several-futures, чтобы он ждал возврата метода.   -  person childofsoong    schedule 18.03.2015
comment
По сути, основной поток запускает асинхронную процедуру, а затем у него заканчиваются инструкции, поэтому он завершается, и это вызывает завершение всех потоков вашей программы, включая все, что выполняется на стороне, обрабатывающей асинхронный вызов.   -  person childofsoong    schedule 18.03.2015
comment
Действительно, вы правы, самым быстрым решением был Thread.sleep. Я буду в будущем реализовывать это в будущем.   -  person Todor Markov    schedule 19.03.2015
comment
Хорошо, я ответил на этом - рад знать, что это все, что было!   -  person childofsoong    schedule 19.03.2015


Ответы (1)


При работе с обратными вызовами вы должны учитывать, что основной поток может легко завершиться до вашего асинхронного вызова, вызывая завершение основного потока (и, соответственно, остальной программы) до того, как асинхронная задача будет завершена и обратный вызов достигнут. Самый простой способ сделать это - вызвать Thread.sleep() и приостановить основной поток на определенное время ожидания. Однако вы можете улучшить это. Один из вариантов - иметь такой фрагмент кода:

var callbackComplete = false
someAsyncMethodWithCallback(callback)
while (!callbackComplete){
    Thread.sleep(100)
}

Затем все, что вам нужно сделать, это включить в обратный вызов строку с надписью callbackComplete = true, и это приведет к его завершению.

Однако это далеко не идеально (но нормально, если вам просто нужно быстрое временное исправление). В идеале вам следует прочитать страницу Futures and Promises в документации Scala. . В нем подробно рассказывается, как правильно обрабатывать Futures, а также как справляться с отказами, и его следует считать подходящим ресурсом для работы с асинхронными вызовами.

person childofsoong    schedule 19.03.2015
comment
Спасибо, я использовал длительный спящий режим, чтобы проверить это, однако мне следует перейти к будущим и обещаниям, поскольку производительность слишком критична, чтобы иметь фиксированное количество сна. - person Todor Markov; 20.03.2015