如何使用 snmp4j 在 SCALA 中获取异步 SNMPv2

How to get Asynchronous SNMPv2 in SCALA with 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: 一行同步版本returns数据就好了...

我正在使用 Scala 2.11.6 和 SNMP4J 2.3

处理回调时,您必须考虑到主线程很容易在您的异步调用之前完成,从而导致主线程(以及程序的其余部分)在异步任务完成之前终止并且回调到达。执行此操作的简单方法是调用 Thread.sleep() 并让您的主线程暂停一段特定的等待时间。但是,您可以对此进行改进。一种选择是使用这样的代码片段:

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

然后您需要做的就是让您的回调包含一行内容 callbackComplete = true,这将使它终止。

但是,这远非理想(但如果您只需要快速临时修复,那很好)。理想情况下,您应该通读 Scala 文档中的 Futures and Promises 页面。它详细说明了如何正确处理 Futures 以及处理失败,并且应该被视为处理异步调用的正确资源。