【问题标题】:Telnet socket gateway to Coldfusion Event Gateway to Connect to Asterisk AMITelnet 套接字网关到 Coldfusion 事件网关以连接到 Asterisk AMI
【发布时间】:2017-02-17 06:14:29
【问题描述】:

我希望我的 ColdFusion 应用程序能够记录通过 Management API 从 Asterisk 主机通过 telnet 流式传输的事件。 ColdFusion 事件网关可以监听特定端口,但不能自己发起连接,所以我需要一个网关,可以发起到 Asterisk 主机的 telnet 连接(在指定端口上)并将流式事件推送到 ColdFusion 服务器(在一个指定端口)。我真的不想重新发明轮子,那么有什么实用程序可以做到这一点吗?

我的术语可能不正确,因为我不是那么专业,但我希望我已经对要求进行了足够的解释! “实用程序”可以驻留在 Linux 或 Windows 平台上。

编辑: 要连接到 Asterisk 主机 telnet 流并通过它进行身份验证,必须发送以下内容:

Action: login<CRLF>
Username: usr<CRLF>
Secret: abc123<CRLF>
<CRLF>

我知道之前发布的问题与此类似(但未得到回答),但我很高兴在 ColdFusion 之外找到解决方案

谢谢

【问题讨论】:

    标签: linux sockets coldfusion asterisk gateway


    【解决方案1】:

    使用 Coldfusion 的 Socket 网关。它是内置的,并且是 Coldfusion 中事实上的功能,可以使用基于 TCP/IP 的协议(例如 Telnet)发送和响应消息,

    【讨论】:

    • 据我所知,ColdFusion Socket Gateway 纯粹是一个监听服务,不能“连接”到流,它只能监听指向它的流。
    • 是的,Coldfusion 的套接字网关不会即时创建连接。它只有一个固定连接,即到它被配置为侦听的端口。然而,它可以向可能大量的客户端发送消息。客户端连接到套接字网关,网关通过其 ID 识别每个客户端。
    • 由于 CF Socket Gateway 无法提供我需要的功能 - 即启动连接以收听,我创建了这个线程。我想使用 CF 套接字网关,但我需要另一个网关/重定向器,而不是可以使用特定端口启动与主机的 telnet 连接,发送身份验证字符串,然后使用该端口将任何流数据转发到 CF 主机分配给 CF 套接字网关。
    【解决方案2】:

    我开始怀疑我是否理解您的要求。您希望您的应用程序“启动连接以收听”。 CF Socket Gateway 可能不会“启动”连接,但它确实“有一个要监听的连接”。为什么要启动你已经拥有的东西?为什么“发起”这个词如此重要?

    无论如何,我将您的要求“使用特定端口启动到主机的 telnet 连接”解释为“连接到另一台服务器上的套接字”。你不需要一个完整的网关/重定向器机器。您可以在 Coldfusion Socket Gateway 的 CFC 中执行此操作。它只需要 2 或 3 行代码(在网上搜索“读取和写入套接字”)。

    因此,在您的最终设计中,您将在两个套接字之间建立连接。一个在您的 Coldfusion 服务器上,另一个在主机服务器上。连接中的通信是双向的。任意数量的客户端,比如 10 000 个,然后可以在 CF 套接字上侦听来自主机服务器的所有消息。

    【讨论】:

    • 我没有使用过 Socket 网关,所以也许我遗漏了一些东西,但我并没有按照您的设想工作。在这种情况下,他们需要 CF 充当 telnet 客户端(本质上)并打开与远程服务器的连接以启动通信和消息交换。文档指出网关无法启动连接。如果是这样,这似乎会让您有两个断开连接的服务器,它们都在侦听和等待 client 连接。你能详细说明一下吗?
    • 英国人说,“布丁的证据在于吃”。我正在寻找时间,在工作之间,编写一个套接字到套接字通信的示例。或者,说明为什么它不起作用。
    • 是的,我最终快速浏览了一下,结果似乎证实它不是这项工作的正确工具,即听众而不是客户。
    • 我仍然想使用 CF Socket Gateway 来接收流数据,但我需要中间那个位,它将连接到 Telnet 流,发送身份验证数据,然后将流转发到CF EG 端口 - 有什么想法吗?
    • @JamesKnight - 虽然您可以使用基于 Java 的 telnet 客户端和 Socket 网关来安装某些东西,但您是否看过 Asterisk Java 库?我在之前的评论中提到过(不小心删除了)。根据我的阅读,该库似乎是专门为您正在做的事情而设计的,即与 Asterisk AMI 交互并为您处理低级套接字内容。当我看到注意到您的最后评论时,我正要发布一个示例...
    【解决方案3】:

    如果您需要做的只是从 Asterisk 服务器捕获事件,我会建议一种不同的方法。

    您似乎正在使用 Asterisk AMI,请查看 Asterisk-Java。根据我的阅读,它是一个 java 库,可以为您处理低级套接字通信和解析,并为与 Asterisk 服务器交互提供更高级别的接口。因此它能够发起连接、捕获事件等等。

    理论上,您可以在应用程序启动时打开连接并注册以接收事件。只要连接保持打开状态,应用程序就会从 Asterisk 接收事件。当应用程序结束时,只需关闭连接即可停止事件。

    初始化连接

    要简单地捕获事件,首先要创建到 Asterisk 服务器的连接。只需提供正确的主机和凭据:

    managerFactory = createObject("java", "org.asteriskjava.manager.ManagerConnectionFactory");
    connection = managerFactory.init( hostNameOrIP
                                     , portNum
                                     , userName
                                     , theSecret ).createManagerConnection();
    

    注册活动

    为了接收事件,您必须首先向连接注册一个ManagerEventListener。通常这需要编写一个自定义的 java 类来实现正确的interface。但是,使用一点 dynamic proxy magic,您可以改用标准 CFC。来自 Asterisk 的任何事件都将直接路由到 CFC,并且可以使用 CF 代码进行处理。

    要添加侦听器,请使用名为 onManagerEvent 的单个函数创建 CFC。只要在 Asterisk 服务器上发生注册事件,就会调用此函数。

    // YourCFCListener.cfc
    component {
        public void function onManagerEvent(any managerEvent)
        {
            // For demo purposes, just output a summary of the event to a log file
            WriteLog( text=arguments.managerEvent.toString(), file="AsteriskListenerLog" );
        }
    }
    

    接下来创建一个代理并将其注册到连接中。

    proxyListener = createDynamicProxy("path.YourCFCListener"
          , [ "org.asteriskjava.manager.ManagerEventListener"] );
    connection.addEventListener( proxyListener );
    

    接收事件:

    要开始接收事件,请登录并连接到服务器。使用掩码指定要接收的事件:"off""on" 或以逗号分隔的特定事件列表(即"system,call,log")。

    // receive ALL events
    connection.login("on");
    

    连接打开后,您将看到写入演示日志文件的事件(假设存在服务器活动)。对于一次性测试,让页面sleep() 几秒钟以允许一些事件流动。然后关闭连接并停止事件:

    sleep(4000);
    connection.logoff()
    

    在真正的应用程序中,您可能会打开一次连接并将其存储在持久范围中,例如应用程序。然后仅在应用程序关闭时关闭它。

    查看 API,您可以使用它做更多事情。但是,以上内容应该提供一个基本的 POC 示例来帮助您开始捕获事件。

    【讨论】:

      【解决方案4】:

      我以通常的方式创建了 Coldfusion Socket Gateway 的一个实例。例如,请参阅https://www.bennadel.com/blog/2173-using-socket-gateways-to-communicate-between-coldfusion-and-node-js.htm

      我得到了以下设置:

      1)监听器CFC的内容(SocketGatewayListener.cfc):

      <cfcomponent>
      
      <cffunction name="onIncomingMessage" returntype="struct" output="false">
      <cfargument name="cfevent" >
      <cfset var msg = {} >
      
      <cfscript>
      /* The code within this cfscript represents the proof of concept.     'xxx.xxx.xxx.xxx' is an IP, 1226 an arbitrary port, so the next line connects to an external socket. Make sure it is listening. */
      var socket = createobject("java","java.net.Socket").init('xxx.xxx.xxx.xxx',1226); 
      var out = createobject("java","java.io.PrintWriter").init(socket.getOutputStream(), true);
      var bufferedWriter = createobject("java","java.io.BufferedWriter").init(out);
      /*Send data to external socket */
      bufferedWriter.write("Authentication data at #now()#");
      bufferedWriter.flush();
      </cfscript>
      
      <cfset msg["message"] = cfevent.data.message>
      
      <cfreturn msg>
      </cffunction>
      
      </cfcomponent>
      

      2) 配置文件内容(socketGateway.cfg):

      # The port the socket server listens on.
      port=9093
      

      3) 我的系统: 冷融合 2016 Windows 7 旗舰版

      网猫: 您可以使用可执行的 nc.exe 来侦听或向套接字网关发送消息。网关运行后,使用 DOS 命令进行侦听,例如

      nc 127.0.0.1 9093
      

      使用类似命令发送消息

      echo 'my test message' | nc 127.0.0.1 9093
      

      大力神 (http://www.hw-group.com/products/hercules/index_en.html): 您可以使用 Hercules GUI 实用程序进行测试。使用它的“TCP Client”向您的套接字网关发送消息,并使用它的“TCP Server”模拟从不同主机监听您的网关的套接字(代码中的 IP 和端口:xxx.xxx.xxx.xxx,第1226章)。

      不幸的是,Adobe Coldfusion 的套接字网关未能如您所愿地向所有正在侦听的套接字广播。您只能让它回复消息的发送者。显然,这是设计使然。这是令人惊讶的。默认情况下,您会期望所有侦听套接字都接收消息。我将向 Coldfusion 团队提出功能请求。

      我在网络上发现了这两种解决方案,它们似乎提供了对所有人广播的功能以及更多功能:

      https://github.com/nmische/cf-websocket-gateway/tree/java-websocket

      https://github.com/softwarezman/cf-socketiogateway

      但是,当我在 Coldfusion 2016 上测试它们时遇到了很多错误。在接下来的日子里,我将向 Coldfusion 附带的 SocketGateway Java 代码添加广播到所有功能。

      【讨论】:

      • 有趣,但我仍然认为这行不通。看起来代码正试图在 onIncomingMessage 中执行此操作,这似乎是一个先有鸡还是先有蛋的场景。在将任何事件流式传输到 onIncomingMessage 之前,必须打开初始连接并登录到 AMI,但是......直到调用 onIncomingMessage 才建立初始连接。所以这是行不通的。 (更不用说在每条消息上打开一个新套接字可能不是一个好主意)。续
      • (Edit -typos) 虽然 OP 中没有详细说明,但从我所读到的内容来看,使用 AMI 最终还有很多事情要做,而不仅仅是打开一个套接字(线程、阻塞、解析响应等)。因此,IMO 他们最好使用其他工具,例如 Asterisk-Java,而不是尝试使用自己的工具。
      • @Leigh,正如我所说,这只是一个概念证明。与前面所说的不同,这表明您实际上可以从套接字网关内建立到套接字的连接并向其发送消息。下一步当然是检查套接字是否存在,以免每次有消息进入时都重新创建它。(网关为所有连接到它的套接字保存一个 ID)。网关不负责打开外部套接字。我特意这么说。该责任在于客户端,即外部主机。这就是 OP 必须采取或离开的设计。
      • BKBK - 我们在这里使用不同的波长 ;-) (.. 或者您可能正在回答不同的问题?)如果您查看 AMI 工作流程,它需要连接 from CF 端, Asterisk 服务器,首先建立。使用 onIncomingMessage 尝试打开该初始连接将不起作用,因为该方法仅在您已经在两者之间建立连接时才会触发。即先有鸡还是先有蛋的场景。这(以及其他原因)就是为什么我说网关不是真正适合这项特定工作的工具。
      • @Leigh,相反,我认为我们在同一个波长上! :) 您正在探索 AMI(作为有需求的客户端)与 Coldfusion 的套接字网关的集成。而我正在探索网关作为服务提供商可以走多远来满足这些要求。您描述的先有鸡还是先有蛋是基于服务应“打开该初始连接”的要求。网关不能,我也是这么说的。它期望客户端建立连接。我的目标是探索网关提供的功能。然后 OP 将知道他是否可以将它用于这项工作。以及为什么。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-23
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      • 2016-09-12
      • 1970-01-01
      • 2016-11-17
      相关资源
      最近更新 更多