通过函数调用从Node.js服务器向客户端发送消息

时间:2015-03-09 21:45:18

标签: javascript node.js socket.io

我想在调用函数时从我的服务器向我的客户端发送消息。使用this answer消息中的代码可以每秒从服务器成功发送到客户端。

我正在构建一个在后台运行节点的应用程序,理想情况下我希望能够单击一个按钮,该按钮将调用节点server.js文件中的一个函数,该文件接受一个参数并将该消息发送给客户端。有问题的功能看起来像这样

function sendToClient(message) {
    clients[0].emit('foo', msg);
}

这会将传入的消息发送给第一个客户端。我怎么能这样做呢?

在终端中,运行node server.js之后有一种方法可以使用终端从服务器文件调用函数,如果是这样,这可能是一种可能的解决方案。

3 个答案:

答案 0 :(得分:4)

现在将消息从服​​务器发送到客户端的最佳方法是使用webSockets。基本概念是:

  1. 客户端A从服务器B加载网页。
  2. 客户端A运行一些javascript,创建与服务器B的webSocket连接。
  3. 服务器B接受该webSocket连接,并且该套接字在网页生命周期内保持打开状态。
  4. 服务器B注册事件处理程序以处理来自网页的传入消息。
  5. 客户端A注册事件处理程序以处理来自服务器的传入消息。
  6. 在任何时间点,服务器都可以主动将数据发送到客户端页面,它将接收该数据。
  7. 在任何时间点,客户端都可以将数据发送到服务器,它将接收该数据。
  8. 支持webSocket支持非常简单的流行node.js库是socket.io。它具有客户端和服务器支持,因此您可以为连接的两端使用相同的库。 socket.io库支持您在问题中提到的.emit()方法,用于通过活动的webSocket连接发送消息。


    您不直接从客户端到服务器调用函数。相反,您发送的消息会触发服务器运行某些特定代码,反之亦然。这是合作编程,其中必须对远程端进行编码以支持您要求它执行的操作,因此您可以向其发送消息和一些可选数据以与消息一起使用,然后它可以接收该消息和数据并执行一些代码。

    因此,假设您希望服务器在温度发生变化时随时告诉客户端,以便客户端可以在其网页中显示更新的温度(我实际上有一个Raspberry Pi node.js服务器就是这样做的)。在这种情况下,客户端网页在页面加载时建立与服务器的webSocket连接。同时,服务器有自己的过程来监控温度变化。当它发现温度已经改变了一些有意义的量时,它会使用新的温度数据向每个连接的客户端发送温度变化消息。客户端接收该消息和数据,然后使用它来更新它的UI以显示新的温度值。

    交易也可能反过来。客户端可能有一个信息矩阵,它希望服务器执行一些复杂的计算。它将使用消息类型中指示的计算类型向服务器发送消息,然后将矩阵作为消息的数据发送。服务器将接收该消息,看到这是对某些数据执行特定类型计算的请求,然后它将调用适当的服务器端函数并将其传递给客户端数据。当结果在服务器上完成时,它会将结果发送回客户端。客户端将收到该结果,然后根据计算结果执行所需操作。


    注意,如果事务只是从客户端到服务器,并且响应然后从服务器返回,则该类型的事务不需要webSocket。这可以通过Ajax调用来完成。客户端对服务器进行ajax调用,服务器制定响应并返回响应。 webSockets最有用的地方是,如果要从服务器启动通信,并在服务器决定的时间将未经请求的数据发送到客户端。为此,您需要在客户端和服务器之间建立连续的连接,这就是webSocket的设计目标。


    看来您可能还有更多关于如何从C#服务器与node.js服务器进行通信的问题,以便它可以通知客户端。如果是这种情况,那么由于node.js服务器已经是一个Web服务器,我只需要添加一个到node.js服务器的路由,这样你就可以简单地从C#服务器向node.js服务器发出一个http请求。将一些数据传递给node.js服务器,然后它可以用来通过上述webSocket连接通知相应的客户端。根据您的安全需求,您可能希望实现某种级别的安全性,以便http请求只能从您的C#服务器本地发送,而不是从外部世界发送到您的node.js服务器。

答案 1 :(得分:2)

为了通过控制台向客户端发送命令,有两个选项,单进程或多进程:

单一过程

  1. 从控制台运行命令时,临时socket.io服务器开始侦听端口。
  2. 客户端连接后,将消息发送给客户端。
  3. 断开并停止控制台应用。
  4. 这样做的原因是socket.io个客户端总是试图连接到服务器。只要浏览器打开,他们就会尝试连接。因此,即使服务器仅启动几秒钟,它也应该连接并接收消息。如果客户端未运行,则只需创建一个超时,该超时将停止控制台应用程序并通知用户它无法广播该命令。

    虽然这种方法非常简单,但它并不健全且效率不高。对于小型项目,这可行,但您可以在下一个方法中获得更好的运气:

    多进程

    当您谈论架构时,这种方法更可靠,可扩展,更好看。这是基本摘要:

    1. 启动与客户端连接的独立服务器。
    2. 创建一个非常类似的控制台node应用,它会向服务器发送消息以转发给客户。
    3. 控制台应用已完成,但主服务器仍然正常运行。
    4. 这种技术只是进程间通信。幸运的是,您已经在主服务器上安装了Socket.IO,因此您的控制台应用程序只需要是另一个socket.io客户端。 Check out this answer on how to implement that.

      这样做的缺点是你必须保护套接字通信。也许您可以强制它只允许localhost个连接,这样您就需要访问服务器才能发送run command消息(您绝对不希望Web客户端在其他网站上执行代码网络客户)。

      总的来说,它归结为您项目的需求。如果您想尝试这是一个快速的小实验,那么只需单个过程即可。但是,如果要托管一个快速服务器(其他网络服务器可用)并且无论如何都需要运行,那么多进程是可行的方法!

      实施例

      我仅使用Socket.io创建了simple example of this进程。运行它的说明都在自述文件中。

      实现

      为了拥有C#(app) - > Node.js(server) - >浏览器(client)通信然后我将执行以下操作之一:

      • 使用redis作为消息队列(使用app将项目添加到队列中,使用server消费,将命令发送到client)。
      • 活在野外,将你的NodeJS和C#运行时与Edge.js合并。如果您可以从C#运行NodeJS,您就可以从appserver发送消息(消息由server处理,就像其他任何socket.io一样客户端 - 服务器模型)。
      • 更容易,但仍然有点hacky,使用System.Diagnostics.Process启动多进程部分中说明的控制台工具。这将简单地使用任意参数运行该过程。不是很强大但值得考虑,简单意味着更难破解(然后,消息由server处理,就像任何其他socket.io客户端 - 服务器模型一样。)

答案 2 :(得分:0)

我会创建一条路由来发送消息并从post参数发送消息。从CLI您可以使用curl或从任何地方:

    app.get('/create', function(req, res) {
            if( data.type && data.content && data.listeners){
                notify( data );
            }
    });

    var notify = function( notification ){
      ns_mynamespace.in(notification.listeners.users)
            .emit("notification", {
                   id: notification.id,
                   title: 'hello', text: notification.content });
            }

    }