在服务器事件上从服务器向客户端发送通知

Posted

技术标签:

【中文标题】在服务器事件上从服务器向客户端发送通知【英文标题】:Send notification from server to client on server event 【发布时间】:2014-08-12 20:13:28 【问题描述】:

如何使用 php 从服务器向客户端发送消息,避免无关的 Ajax 调用。

这是一个想法:

    用户:Alice 进行了更改并发送到服务器。

    服务器然后检查哪些用户不是最新的,如果不是,则调用一些代码将与更改有关的信息发送给 Bob(在这种情况下他不是最新的)。

如何向 Bob 发送消息?

【问题讨论】:

如果您对 Stack Exchange 使用的确切工具和技术感兴趣,那么 this question on Meta Stack Exchange 将对您有用。就实际实现具有类似功能的东西而言,这个问题太宽泛了。 @MatthewStrawbridge 阅读帖子,我谈谈为什么这不起作用。 @user3765372 您想要的是 websockets(如果您希望支持它们,则只能在古代浏览器中使用 ajax 进行长轮询)。如果您无法重新提出您的问题,我会调查一下,此时您的问题可能是特定于实现的,并且更容易提问。 我重新打开了它,因为我认为它是有责任的,并且是一个 很好 的机会,让某人通过对 websockets 的全面概述以及如何依靠 longpolls 来扼杀答案如果它们不可用(我以为我们有,但我找不到)。不过,社区可以覆盖我 (associated meta discussion) @TimPost 感谢您提供有关 Web Sockets 的信息!这正是我所需要的! 【参考方案1】:

您可以使用Server Sent Events。

这些是 websocket 经常被忽视的表亲,重量更轻,而且是一种方式。它们本质上允许客户端等待来自服务器的消息(然后您可以通过不同的通道,例如 AJAX 来响应)

示例客户端代码:

var source = new EventSource('/newFile');

source.addEventListener('message', function(e) 
  // Use AJAX and pull new file here
, false);

不幸的是,似乎(当然)有no IE support。可以使用诸如EventSource HQ 之类的库来支持跨浏览器服务器发送的事件。它将抽象出处理魔鬼浏览器的需要。

【讨论】:

为 w3.org/TR/eventsource - github.com/Yaffle/EventSource 和 github.com/remy/polyfills/blob/master/EventSource.js 填充。当然,还会有更多,但上面的这些都适用于 IE。【参考方案2】:

您正在寻找的是(现在)很常见的东西,有时被称为“实时网络”。它是让您的服务器端代码实时将内容推送到连接的客户端的能力。

这可以通过最新浏览器(和服务器)支持的一些新机制以及其他一些并非真正设计用于执行此操作但可以用作“黑客”的机制来实现工作。

您首先要了解的是,您所要求的(服务器“推送”消息给客户端)并不是网络(或至少是 http)的样子(或者更好,)旨在工作。 经典的 Web 是无状态的、请求-响应、半双工:客户端发起通信,打开与服务器的连接,服务器提供服务,然后关闭连接。 而且过去没有办法让服务器向 Web 客户端发送消息:客户端(即您的浏览器)应该支持反向模型(提供它侦听的端点),从而成为有效的服务器。

这或多或少是像WebSockets 这样的新标准所提供的(另一个值得一提的标准是Server-sent events (SSE);但是,它的支持甚至比WebSockets 还要少,而且它们似乎更倾向于“流式传输”内容而不是发送单个消息)。

与 HTTP 不同,WebSocket 提供全双工通信(任何一方都可以发起),这正是您所寻找的。 在 Firefox 6、Safari 6、Google Chrome 14、Opera 12.10 和 Internet Explorer 10 中实现了正确版本的 WebSocket 协议(某些浏览器中存在旧的、有缺陷的实现)。

那么,如果您的浏览器不支持 WebSockets 怎么办?你必须使用我前面提到的那些“技巧”。那些“诡计”属于Push technologies的伞下。

特别是,一种常见的技术是长轮询。 顾名思义,它不是“推”;长轮询是轮询,即“拉”技术,但它允许模拟推送机制。 使用长轮询时,客户端向服务器请求信息的方式与普通 AJAX 调用完全相同,只是它发出 HTTP/S 请求(轮询)的频率要慢得多。

连接后,服务器(您的服务器、您的 API:servlet、HTTP 处理程序、REST 控制器等等!它通常与您为标准 AJAX 调用提供支持的机制相同)发送一些信息(如果存在)已经有可用的更新;如果没有新内容,它不会发送空响应,而是保持请求打开并等待响应信息可用。

您有一个“传统的”客户端发起的请求,但该请求被“搁置”,直到服务器想要与您通信的内容。 一旦有东西,服务器就会向客户端发送一个响应(通过 HTTP 通道,仍然打开!),完成打开的 HTTP 请求。

可以使用其他技术(例如使用插件提供的套接字 - Silverlight、Java 小程序、Flash..),但同样要利用它们,您需要正确的客户端(浏览器/插件组合)。

当然,您可以自己实现所有这些东西。我鼓励您尝试作为学习练习

对于您的生产代码,您最好使用封装所有这些概念和技术的库,例如 SignalR(用于 ASP.NET)Ratchet(用于 PHP)、Signal.IO(用于 node.js)、@ 987654328@(用于 Ruby)....其中一些库将实现不止一种技术,根据客户端选择最佳技术,然后自动回退到其他技术。他们真的为您省去了很多麻烦!

【讨论】:

【参考方案3】:

正如 cmets 中所说,您正在寻找的技术是 WebSockets。它们是您在服务器和 Web 浏览客户端之间建立套接字(unix 术语,表示基本双向管道)的一种方式。

虽然可以使用原始 websocket api。我更喜欢使用像 Socket.IO 这样的库来为我抽象出令人讨厌的细节。

按照通常的方式安装软件包后(假设您使用的是节点),Socket.IO 为您提供了许多不同的简单方法,例如将事件和广播集成到您的应用程序中。您也可以将其用作just a cross browser websocket(它为不支持 websockets 的浏览器实现后备长轮询)。

对于您的情况,当服务器上的文件发生更改时,您可能希望从服务器向客户端发送一条消息。

一个服务器端(Node.js):

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) 
  socket.on('message', function ()  );
  socket.on('disconnect', function ()  );

  // more stuff here
  if(somethingChanged) 
    socket.send(JSON.stringify(changed: true, file: 'file1.txt', newContent: 'Im fresh off the press yo!');
  
);

对于客户:

<script>
  var socket = io('http://localhost/');
  socket.on('connect', function () 
    socket.send('anything-new');

    socket.on('message', function (msg) 
      if(JSON.parse(msg).changed) 
        // Do stuff here
      
    );
  );
</script>

虽然这是一个非常简单的示例,但希望足以让您入门。

【讨论】:

以上是关于在服务器事件上从服务器向客户端发送通知的主要内容,如果未能解决你的问题,请参考以下文章

如何在 GlassFish 上从 JAX-WS 向 Swing 客户端构建推送通知?

在节点 js 中向移动设备发送通知

向特定用户发送通知

Java - 如何从服务器向客户端发送通知

向所有客户端发送推送通知?

Zookeeper互联网大厂高频面试题—2