`
zha_zi
  • 浏览: 592992 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

websocket server-sent polling 对比

 
阅读更多

社交网络如此流行,以至于所有的厂商都想在他们的网站中加入一些新的特性,例如有些需要即时的通知。这是非常常见的需求,设想你打开一个页面后,你肯定想你收到的通知,好友的状态列表等等即时的展现出来。原来的web设计就是一种方法,一个请求,一个相应,而现在在HTML5的帮助下对于服务器和客户端的通信来讲,我们有了新的办法。虽然现在还是有很多人在使用Long-polling技术模拟服务器和客户端的通信。

随着web浏览器的更新换代,现在已经有相当的一部分浏览器具有了比较新的非常酷的特性。有相当大的一部分浏览器支持HTML5 cmmunication API,是否时候抛弃long-polling了?让我们拭目以待。

如果您的网站有任何需要告知用户的通信,那么这个测试对您就有帮助。很简单,这个测试就是用户获取私人信息,在通知用户未读信息的时候,我们采用long-polling、Server-Sent Events和WebSockets的方式实现,然后比较结果。

首先让我们来看一下例子中基础的代码,我们需要一个访问数据库的库,一个获取未读通知数量和添加一个新的通知的模型。

我们需要一张数据库表:

1 CREATE TABLE IF NOT EXISTS `notification` (
2   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
3   `recipientUid` int(10) unsigned NOT NULL,
4   `eventId` int(10) unsigned NOT NULL,
5   `isNew` tinyint(1) unsigned NOT NULL DEFAULT '1',
6   PRIMARY KEY (`id`),
7   KEY `IX_recipientUid` (`recipientUid`),
8   KEY `IX_isNew` (`isNew`)
9 ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='User notifications';

获取未读通知数量和添加通知的模型:

01 <?php
02 class Model_UserNotification
03 {
04    private $_db;
05  
06  
07    public function  __construct(Lib_Db $db)
08    {
09         $this->_db = $db;
10    }
11    /**
12     *
13     * @param int $recipientUid
14     * <span>@return</span>  int
15     */
16    public function fetchNumberByRecipientUid($recipientUid)
17    {
18        return $this->_db->fetch("SELECT count(*) as count "
19            " FROM notification WHERE recipientUid = %d AND isNew = 1"
20            $recipientUid)->count;
21    }
22    /**
23     *
24     * @param int $recipientUid
25     * @param int $eventId
26     */
27    public function add($recipientUid$eventId)
28    {
29        $this->_db->update("INSERT INTO "
30            " notification (`id`, `recipientUid`, `eventId`, `isNew`) VALUES (NULL, '%d', '%d', '1')"
31            $recipientUid$eventId);
32    }
33    /**
34     *
35     * @param int $recipientUid
36     */
37    public function removeAll($recipientUid)
38    {
39        $this->_db->update("DELETE FROM "
40            " notification WHERE recipientUid = %d"
41            $recipientUid);
42    }
43 }

long-polling

运行原理

浏览器通过HTTP发送一个带有接收者ID(这里是user)的请求和当前状态(当前展示的未读通知的数量)到服务器。这将创建一个进程,这个进程一直查询数据库直到状态改变为止,当状态改变的时候,客户端就收到了服务器的相应,它可以更新自己的展示,而后发出下一个请求。

实现方式

客户端就是简单的两个input输入框,一个展示未读消息数量,一个展示上次消息到达的时间。JavaScript通过AJAX的方式向服务器发送接收者用户id和当前的状态(当前页面上展示的未读通知数量)。使用JSONP处理跨域。

01 ...
02 <p>Recipient id: <?= $recipientUid ?></p>
03 <p>Notifications: <input id="notificationNum" size="4" name="some" value="<?= $displayedNotificationNum ?>" /></p>
04 <p>Last event arrived at: <input id="time" size="12" name="some" value="0" /></p>
05  
06 <script type="text/javascript">
07  
08 (function( $ ) {
09  
10 var UID = <?= $recipientUid ?>;
11  
12 $.NotifierLongPolling = (function() {
13     var _stateNode = $('#notificationNum'), _timeNode = $('#time');
14     return {
15         onMessage : function(data) {
16             _stateNode.val(data.updatedNotificationNum);
17             _timeNode.val(data.time);
18             setTimeout($.NotifierLongPolling.send, 3000);
19         },
20         send : function() {          
21             $.ajax({
22                     'url': 'server.php',
23                     'type': 'POST',
24                     'dataType': 'jsonp',
25                     'jsonpCallback': '$.NotifierLongPolling.onMessage',
26                     'data': 'recipientUid=' + UID + '&displayedNotificationNum='
27                         + _stateNode.val()
28             });
29         }
30     }
31 }());
32  
33 // Document is ready
34 $(document).bind('ready.app', function() {
35    setTimeout($.NotifierLongPolling.send, 40);
36 });
37  
38 })( jQuery );
39  
40  
41 </script>

服务器等待3秒,然后检查状态是否改变,如果状态改变了则响应请求,否则继续等待,然后查询。

01 //...
02 $recipientUid = (int)$_REQUEST["recipientUid"];
03 $displayedNotificationNum = (int)$_REQUEST["displayedNotificationNum"];
04 $secCount = 0;
05  
06 do {
07     sleep(IDLE_TIME);
08     $updatedNotificationNum $model->fetchNumberByRecipientUid($recipientUid);
09 while ($updatedNotificationNum == $displayedNotificationNum);
10  
11 header("HTTP/1.0 200");
12 printf ('%s({"time" : "%s", "updatedNotificationNum" : "%d"});'
13     $_REQUEST["callback"], date('d/m H:i:s'), $updatedNotificationNum);

客户端收到服务器返回的状态,然后展示出来,接下来再次发送请求。

Server-Sent Events

运行原理

浏览器通过HTTP向服务器发送请求,服务器端拿出数据库中的最新的信息,立即返回给客户端,客户端等待三秒后再次发出下一个请求。

实现方式

同样,浏览器中HTML两个input,JavaScript模块打开EventSource,把接受者的id传给服务端。

01 ...
02 <p>Recipient id: <?= $recipientUid ?></p>
03 <p>Notifications: <input id="notificationNum" size="4" name="some" value="<?= $displayedNotificationNum ?>" /></p>
04 <p>Last event arrived at: <input id="time" size="12" name="some" value="0" /></p>
05  
06 <script type="text/javascript">
07  
08 (function( $ ) {
09  
10 var UID = <?= $recipientUid ?>;
11  
12 NotifierSSE = (function() {
13     var _stateNode = $('#notificationNum'),
14         _timeNode = $('#time'),
15         _src,
16         _handler = {
17         onMessage : function(event) {           
18              var data = JSON.parse(event.data);
19             _stateNode.val(data.updatedNotificationNum);
20             _timeNode.val(data.time);
21         }
22     };
23     return {
24         init : function () {
25         _src = new EventSource("server.php?recipientUid=" + UID);
26         _src.addEventListener('message', _handler.onMessage, false);
27         }
28     }
29 }());
30  
31  
32 // Document is ready
33 $(document).bind('ready.app', function() {
34    setTimeout(NotifierSSE.init, 40);
35 });
36  
37 })( jQuery );
38  
39 </script>

服务器端将最新的未读消息数量返回给客户端。

01 //...
02 header('Content-Type: text/event-stream');
03 header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
04  
05 $recipientUid = (int)$_REQUEST["recipientUid"];
06  
07 function send($updatedNotificationNum)
08 {
09     printf ("id: %s\n\n", PROC_ID);
10     printf ('data: {"time" : "%s", "updatedNotificationNum" : "%d"}' "\n\n"
11         ,date('d/m H:i:s') , $updatedNotificationNum);
12     ob_flush();
13     flush();
14 }
15  
16 while (true) {
17     send($model->fetchNumberByRecipientUid($recipientUid));
18     sleep(IDLE_TIME);
19 }
20 //...

客户端收到相应后,onMessage事件的处理器将被调用。浏览器将每3秒发送一个请求,除非将连接关闭(Close方法)。

WebSockets

运行原理

客户端通知WebSockets服务器一个事件,告诉他接收者id,服务器将立即通知消息,当任何新的未读消息来的时候,服务器都将立即返回数据给客户端。

01 <p>Recipient id: <?= $recipientUid ?></p>
02     <p>Notification: <span id="display"></span></p>
03     <button id="test">Fire an event</button>
04  
05 <script>
06     realtime = new realtimeComm(window.location.host + ":20001");
07     realtime.addListener('/notification/updates', function(response) {
08         $('#display').html('Client #' + response.data.recipientUid + ' broadcast an action #' + response.data.actionId);
09     });
10  
11     $('#test').bind('click', this, function(e){
12         e.preventDefault();
13  
14         realtime.send('/notification/presence', {
15             'actionId': 1,
16             'recipientUid': <?= $recipientUid ?>
17         }, function() {});
18  
19     });
20  
21 </script>

客户端打开一个WebSockets连接而且在/notification/updates上订阅一个事件处理。在HTML中添加一个发送向/notification/presents发送接收者id的button。这将在所有的打开连接中引起广播消息。所以每一个活跃的客户端都收到通知,客户端会检查消息中的id是否是当前登录的用户的id,如果是就更新通知数量。

总结

浏览器兼容性

  • Long-polling支持大多数当前的浏览器
  • Server-Sent Events支持Chrome9+、Firefox6+、Opera11+、Safari5+
  • Chrome14、Firefox7支持最新的hybi-10协议,Firefox6支持hybi-07.

服务器负载

  • Long-polling占一小部分CPU资源,但是创建空的进程将浪费系统的内存
  • Server-Sent Events工作的方式有很多,除非Server-Sent Events不必在每一次响应发出后都关闭连接。
  • WebSockets,服务器只需要一个进程处理所有的请求,没有循环,不必为每个客户端都分配cpu和内存。

客户端负载

  • Long-polling取决于实现方式,但终究是一个异步的方式
  • Server-Sent Events采用浏览器的内置的实现方式,只花费很少的一部分资源。
  • WebSockets跟Server-Sent Events一样,采用浏览器的内置的实现方式,只花费很少的一部分资源。

时间线

  • Long-polling接近实时,但是发送新的请求和发送相应会有一定的时延。
  • Server-Sent Events默认延时3秒,但是可以调整。
  • WebSockets真正的实时

实现方式复杂度

  • Long-polling实现起来非常简单
  • Server-Sent Events甚至比Long-polling更简单
  • 需要一个WebSockets服务器处理事件,并开放一个端口
分享到:
评论

相关推荐

    服务端推技术 - Server-side Push 多示例

    3. **EventSource/SSE(Server-Sent Events)**:这是一种单向的推送机制,服务器可以将事件以文本流的形式持续发送到客户端。与WebSocket相比,SSE更简单,但只能从服务器向客户端推送数据。 在"comet_broadcast.a...

    Android Websocket

    WebSocket与传统的Long Polling、Polling、Server-Sent Events (SSE)等推送技术相比,具有更低的延迟和更高的效率。尤其是对于Android这样的移动平台,WebSocket能更好地节省电池和网络资源。 七、实际开发注意事项...

    .net 服务器推送

    它支持多种后端技术(如ASP.NET Core或ASP.NET)和多种传输方式(包括WebSocket、Long Polling、Server-Sent Events等)。SignalR提供了简单的API,使得在C#中实现服务器推送变得容易,只需几行代码即可实现连接、...

    C#websocket.zip

    SignalR是一个流行的库,它不仅支持WebSocket,还支持其他几种回退机制(如Long Polling、Server-Sent Events),以确保在不支持WebSocket的环境中也能提供类似的功能。SignalR处理了握手、连接管理和错误处理等复杂...

    WebSocket兼容到低版本浏览器

    2. Server-Sent Events (SSE) 或者 Long Polling:这些是WebSocket的替代技术,可以实现服务器向客户端的单向推送。SSE使用HTTP流,而Long Polling则通过保持长时间打开的HTTP请求来模拟双向通信。这些方法虽然不如...

    WebSocket的简单实现

    此外,还可以使用第三方库如SignalR,它提供了一层抽象,简化了WebSocket的使用,同时也支持回退到其他实时通信技术,如Long Polling或Server-Sent Events。 在压缩包中的"WebSocketSample-master"文件可能是包含了...

    ASP.NET(C#) ServerPush

    它抽象了底层的传输协议(包括WebSocket、Long Polling、Server-Sent Events等),简化了开发者的工作。 3. **Long Polling**:在WebSocket不支持或不可用的情况下,Long Polling是一个常见的ServerPush技术。...

    nodejs-chats-using-longpolling-eventsourcing-websockets-ulbitv:使用3种不同方式聊天的Node.js应用

    接下来,我们讨论**事件源(Server-Sent Events, SSE)**。SSE是一种更现代的技术,允许服务器向客户端推送事件。通过建立一个单向的HTTP连接,服务器可以随时向客户端发送数据流,而无需客户端不断地重新发起请求。...

    Best HTTP2 2.6.3

    它简化了在Web应用中实现双向通信的过程,支持多种底层传输方式,包括WebSocket、Long Polling和Server-Sent Events等。SignalR Core可以用于构建聊天应用、实时仪表盘、协同编辑器等需要实时更新功能的应用。 ...

    JavaWeb后台自动向前台发送消息

    这种技术通常被称为“服务器推送”(Server-Sent Events, SSE)或“Comet”技术。本项目利用了Comet4J这一第三方库来实现这一功能,下面将详细讲解其原理和实现方式。 Comet4J是一个基于Java的服务器推送框架,它...

    asp.net server push 长连接

    SignalR处理了连接管理、心跳检测、重连逻辑,以及多种传输方式(如WebSocket、Server-Sent Events、Long Polling)的自动选择和切换,使得开发者可以专注于业务逻辑而不是底层网络细节。 2. **WebSocket**:...

    SignalR完整源码

    SignalR利用多种技术(如WebSocket、Server-Sent Events、Long Polling)来提供跨平台的实时通信,无论浏览器或服务器是否支持WebSocket,SignalR都能自动选择最佳的通信机制。 标题“SignalR完整源码”表明这是一...

    MVC双通道协议实现服务器推.rar

    SignalR支持多种传输方式,包括WebSocket、Server-Sent Events、Forever Frame(IFrame长时间连接)以及Long Polling,这些机制都是实现服务器推的关键技术。在SignalR中,服务器和客户端之间的通信可以通过Hub协议...

    Developing RESTful Services with JAX-RS 2.0, WebSockets, and JSON

    首先,本书从不同客户端/服务器通信模型讲起,包括客户端轮询(client polling)、服务器发送事件(Server-Sent Events)和WebSocket等,这表明了现代Web应用开发对于不同通信模式的需求。在本书中,读者将学会如何...

    WebSocket SignalR实时在线聊天室.zip

    SignalR提供了多种传输机制,包括WebSocket、Server-Sent Events (SSE)、Forever Frame和Long Polling,它会根据浏览器和服务器的兼容性自动选择最合适的传输方式。在支持WebSocket的环境中,SignalR会优先使用...

    WebSocket学习文档

    3. **Comet技术**:包括服务器推(Server-Sent Events, SSE)和流(Streaming)等,让服务器能够向客户端推送数据。但Comet技术复杂,兼容性较差。 WebSocket则提供了一种更为高效和简洁的解决方案。它允许服务器在...

    ASP.NET 开发基于BS方式的即时通讯软件的设计与实现(源代码+论文)

    SignalR支持多种传输机制,包括WebSocket、Server-Sent Events、Forever Frame和Long Polling,能自动选择最适合当前环境的传输方式。 4. **数据库设计**:IM系统的数据存储通常涉及用户信息、好友关系、聊天记录等...

    ServerPush(服务器推送)

    SignalR支持多种传输方式,包括WebSocket、Server-Sent Events、长期轮询等,并自动根据浏览器和服务器的能力选择最佳的传输方式。SignalR提供了Hub接口,使得开发者可以轻松地在服务器和客户端之间发送和接收消息。...

    .net实现Server Push(服务器推送)源码

    4. **SignalR**:.NET平台的一个库,简化了实时Web应用的开发,支持WebSocket、Server-Sent Events(SSE)、Long Polling等多种推送机制。 在`ServerPush`源码中,可能会有以下几个关键部分: - 连接管理:负责...

    消息推送实例

    为了解决这个问题,出现了长轮询(Long Polling)、WebSocket、Server-Sent Events (SSE) 等技术,它们允许服务器在有新数据时主动推送给客户端,实现了真正的双向通信。 RTPollingDemo-master中的“RTPolling”...

Global site tag (gtag.js) - Google Analytics