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

use*_*372 13 php ajax client-server

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

这是一个想法:

  1. 用户:Alice进行了一次更改,并将其发送到服务器.

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

如何向Bob发送消息?

sec*_*ula 21

您可以使用Server Sent Events.

这些是经常看起来很像重量轻且单向的腹板的表兄弟.它们基本上允许客户端等待来自服务器的消息(然后您可以通过不同的通道(如AJAX)进行响应)

示例客户端代码:

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

source.addEventListener('message', function(e) {
  // Use AJAX and pull new file here
}, false);
Run Code Online (Sandbox Code Playgroud)

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


Lor*_*tté 15

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

这可以通过最新浏览器(和服务器)支持的一些新机制,以及其他一些并非真正设计用于实现这一目标的机制实现,但可以用作"黑客"使其工作.

你要了解的第一件事是,你所要求的(服务器"推"消息到客户端)是网络(或者,至少,HTTP)不是如何(或更好,),旨在工作.经典Web是无状态,请求 - 响应,半双工:客户端启动通信,打开与服务器的连接,服务器提供服务,连接关闭.并且以前服务器无法向Web客户端发送消息:客户端(即您的浏览器)应该支持反向模型(提供它侦听的端点),成为有效的服务器.

这或多或少是像WebSockets这样的新标准提供的(另一个标准值得一提的是服务器发送事件(SSE) ;但是,它的支持甚至比WebSockets更稀缺,并且它们似乎比发送单个"流"内容更容易消息).

与HTTP不同,WebSocket提供全双工通信(任何一方都可以启动它),这正是您正在寻找的.WebSocket协议的正确版本(某些浏览器中存在较旧的错误实现)在Firefox 6,Safari 6,Google Chrome 14,Opera 12.10和Internet Explorer 10中实现.

那么,如果您的浏览器不支持WebSockets,该怎么办?你必须使用我前面提到的那些"技巧".这些"伎俩"属于推动技术的喧嚣.

特别是,常见的技术是长轮询.就像名字所说,它不是"推"; 长轮询是轮询,即"拉"技术,但它允许模拟推送机制.通过长轮询,客户端完全按照正常的AJAX调用从服务器请求信息,除非它以更慢的频率发出HTTP/S请求(轮询).

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

您有一个"传统的"客户端发起的请求,但是在服务器想要与您通信之前,它会被"暂停".一旦有东西,服务器就会向客户端发送一个响应(通过HTTP通道,仍然打开!),完成打开的HTTP请求.

可以使用其他技术(比如使用插件提供的套接字 - Silverlight,Java applets,Flash ..),但是再次使用它们需要正确的客户端(浏览器/插件组合).

当然,你可以自己实现所有这些东西.我鼓励你尝试学习练习.

对于您的生产代码,您最好使用一个封装所有这些概念和技术的库,如SignalR(适用于ASP.NET)Ratchet(适用于PHP),Signal.IO(适用于node.js),Faye(适用于Ruby)......其中一些库将实现多种技术,选择基于客户端的最佳技术,自动回退到其他库.他们真的给你带来了很多麻烦!


sec*_*ula 8

正如评论中所说,您正在寻找的技术是WebSockets.它们是您在服务器和Web浏览客户端之间使用套接字(unix术语,用于基本的bidrectional管道)的一种方式.

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

在正常情况下安装软件包之后(假设您正在使用节点)Socket.IO为您提供了许多不同的简单方法,例如集成到您的应用程序中的事件和广播.您也可以将它用作一个跨浏览器的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!'});
  }
});
Run Code Online (Sandbox Code Playgroud)

对于客户:

<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>
Run Code Online (Sandbox Code Playgroud)

虽然这是一个非常简单的例子,但希望能让你开始.