Facebook,Gmail如何发送实时通知?
我已经阅读了关于这个主题的一些post,答案是彗星,反向Ajax,HTTPstream媒体,服务器推动等。
Gmail上的收到邮件通知如何工作?
GMail Chat如何在没有客户端交互的情况下发出AJAX请求?
我想知道是否有任何代码引用,我可以按照写一个非常简单的例子。 许多职位或网站只是谈论技术。 很难find一个完整的示例代码。 另外,似乎有很多方法可以用来实现这个彗星,比如Hidden IFrame,XMLHttpRequest。 在我看来,使用XMLHttpRequest是一个更好的select。 你怎么看待不同方法的优劣? Gmail使用哪一个?
我知道它需要在服务器端和客户端进行。 有没有PHP和JavaScript示例代码?
Facebook做这件事的方式非常有趣。
执行这种通知的一种常见方法是在给定的时间间隔(可能每隔几秒)在服务器上轮询脚本(使用AJAX),以检查是否发生了一些事情。 然而,这可能是相当networking密集的,而且你经常做毫无意义的请求,因为什么也没有发生。
Facebook做它的方式是使用彗星方法,而不是在一个时间间隔内进行轮询,只要一次轮询完成,它就发出另一个轮询。 但是,对服务器上的脚本的每个请求都有一个非常长的超时时间,并且服务器只会在发生事件时才响应请求。 如果您在Facebook上调出Firebug的控制台标签,您可以看到发生这种情况,请求脚本可能需要几分钟时间。 这真的很巧妙,因为这种方法立即减less了请求的数量,以及你多久发送它们。 你现在有一个事件框架,允许服务器“触发”事件。
在这个背后,从这些民意调查返回的实际内容方面,这是一个JSON响应,看起来是一个事件列表和关于它们的信息。 它被缩小了,所以有点难以阅读。
就实际技术而言,AJAX就是要走这里的路,因为你可以控制请求超时等等很多事情。 我build议(这里堆栈溢出陈词滥调)使用jQuery来做AJAX,它会带走很多的交叉兼容性问题。 在PHP方面,您可以简单地轮询您的PHP脚本中的事件日志数据库表,并且只有在发生某些事情时才返回给客户端。 我期望有许多方法来实现这一点。
实现:
服务器端:
在PHP中似乎有一些彗星库的实现,但说实话,它确实非常简单,可能类似于下面的伪代码:
while(!has_event_happened()) { sleep(5); } echo json_encode(get_events());
-
has_event_happened函数只是检查事件表中是否有任何事情发生,然后get_events函数会返回表中新行的列表? 取决于问题的背景。
-
不要忘记改变你的PHP最大执行时间,否则会超时!
客户端:
看看做Comet交互的jQuery插件:
- 项目主页: http : //plugins.jquery.com/project/Comet
- Google代码: https : //code.google.com/archive/p/jquerycomet/ – 在Subversion存储库中似乎有某种示例用法。
也就是说,这个插件似乎增加了一点复杂性,它在客户端上确实非常简单,也许(使用jQuery)是这样的:
function doPoll() { $.get("events.php", {}, function(result) { $.each(result.events, function(event) { //iterate over the events //do something with your event }); doPoll(); //this effectively causes the poll to run again as //soon as the response comes back }, 'json'); } $(document).ready(function() { $.ajaxSetup({ timeout: 1000*60//set a global AJAX timeout of a minute }); doPoll(); // do the first poll });
整个事情很大程度上取决于你现有的架构如何组合在一起。
更新
当我继续收到对此的赞扬时,我认为这是合理的记住,这个答案是4岁。 networking的发展速度非常快,请注意这个答案。
我最近有同样的问题,并就这个问题进行了研究。
给出的解决scheme被称为长轮询,要正确使用它,你必须确保你的AJAX请求有一个“大”超时,并总是在当前结束(超时,错误或成功)后发出此请求。
长轮询 – 客户端
在这里,为了保持代码简洁,我将使用jQuery:
function pollTask() { $.ajax({ url: '/api/Polling', async: true, // by default, it's async, but... dataType: 'json', // or the dataType you are working with timeout: 10000, // IMPORTANT! this is a 10 seconds timeout cache: false }).done(function (eventList) { // Handle your data here var data; for (var eventName in eventList) { data = eventList[eventName]; dispatcher.handle(eventName, data); // handle the `eventName` with `data` } }).always(pollTask); }
记住这一点很重要(从jQuery文档 ):
在jQuery 1.4.x及以下版本中,如果请求超时,XMLHttpRequest对象将处于无效状态; 访问任何对象成员可能会抛出exception。 仅在Firefox 3.0+中,脚本和JSONP请求不能被超时取消; 脚本即使在超时时间到达后也会运行。
长轮询 – 服务器
这不是用任何特定的语言,而是这样的:
function handleRequest () { while (!anythingHappened() || hasTimedOut()) { sleep(2); } return events(); }
在这里, hasTimedOut
将确保您的代码不会永远等待,并且发生anythingHappened
,将检查是否有任何事件发生。 sleep
是释放你的线程做其他的事情,而什么都没有发生。 events
将以JSON格式(或您喜欢的任何其他方式)返回events
字典(或者您可能喜欢的任何其他数据结构)。
它肯定可以解决这个问题,但是,如果您担心研究时的可扩展性和性能问题,可以考虑另一种解决scheme。
解
使用套接字!
在客户端,为了避免任何兼容性问题,请使用socket.io 。 它试图直接使用套接字,并且在套接字不可用时具有回退到其他解决scheme的function。
在服务器端,使用NodeJS创build一个服务器( 这里的例子)。 客户端将订阅由服务器创build的这个频道(观察者)。 无论何时必须发送通知,都将在此通道中发布,并通知下标(客户端)。
如果你不喜欢这个解决scheme,试试APE( Ajax Push Engine )。
希望我帮助。
根据有关Facebook消息系统的幻灯片 ,Facebook使用慧星技术向networking浏览器“推送”消息。 Facebook的彗星服务器build立在开源的Erlangnetworking服务器mochiweb上。
在下面的图片中,“通道簇”这个短语的意思是“彗星服务器”。
许多其他大型网站都build立了自己的慧星服务器,因为每个公司的需求都有所不同。 但是在开源慧星服务器上构build自己的慧星服务器是个不错的方法。
你可以试试icomet ,一个用libevent构build的C1000K C ++慧星服务器。 icomet还提供了一个JavaScript库,使用起来非常简单:
var comet = new iComet({ sign_url: 'http://' + app_host + '/sign?obj=' + obj, sub_url: 'http://' + icomet_host + '/sub', callback: function(msg){ // on server push alert(msg.content); } });
icomet支持多种浏览器和操作系统,包括Safari(iOS,Mac),IE(Windows),Firefox,Chrome等。
Facebook使用MQTT而不是HTTP。 推动比投票更好。 通过HTTP我们需要连续轮询服务器,但通过MQTT服务器将消息推送到客户端。
MQTT和HTTP之间的比较: http : //www.youtube.com/watch?v = -KNPXPmx88E
注意:我的答案最适合移动设备。
长轮询的一个重要问题是error handling。 有两种types的错误:
-
在这种情况下,请求可能会超时,客户端应立即重新build立连接。 当没有消息到达时,这是长轮询中的正常事件。
-
networking错误或执行错误。 这是客户端应该优雅地接受并等待服务器重新联机的实际错误。
主要的问题是,如果你的error handling程序立即也为types2错误重新build立连接,客户端将DOS服务器。
这两个代码示例的答案都会丢失。
function longPoll() { var shouldDelay = false; $.ajax({ url: 'poll.php', async: true, // by default, it's async, but... dataType: 'json', // or the dataType you are working with timeout: 10000, // IMPORTANT! this is a 10 seconds timeout cache: false }).done(function (data, textStatus, jqXHR) { // do something with data... }).fail(function (jqXHR, textStatus, errorThrown ) { shouldDelay = textStatus !== "timeout"; }).always(function() { // in case of network error. throttle otherwise we DOS ourselves. If it was a timeout, its normal operation. go again. var delay = shouldDelay ? 10000: 0; window.setTimeout(longPoll, delay); }); } longPoll(); //fire first handler