哪种网络协议用于远程应用程序的轻量级通知?

时间:2010-04-20 14:12:16

标签: delphi protocols notifications soap-client

我有这种情况...... 客户端启动的SOAP 1.1通信在一台服务器之间,比方说,成千上万的客户端。客户端是外部的,通过我们的防火墙进入,通过证书,https等进行身份验证。它们可以在任何地方,通常有自己的防火墙,NAT路由器等......它们真的是外部的,而不仅仅是远程公司办公室。他们可能在企业/校园网络,DSL /电缆,甚至是拨号。

客户端使用Delphi(2005年+ 2007年的SOAP修复),服务器是C#,但从架构/设计的角度来看,这无关紧要。

目前,客户端将新数据推送到服务器,并在15分钟的轮询循环中从服务器提取新数据。服务器当前不推送数据 - 客户端点击“messagecount”方法,以查看是否有新数据需要提取。如果为0,则再睡15分钟并再次检查。

我们试图将其降低到7秒。

如果这是一个内部应用程序,只有一个或几个客户端,我们会写一个无声的“监听器”肥皂服务,并将数据推送到它。但由于它们是外部的,所以坐在自己的防火墙后面,有时甚至是NAT路由器后面的专用网络,这是不切实际的。

所以我们离开了更快的循环轮询。每10秒检查一次消息数量的10K客户端将是1000 /秒的消息,这些消息大多只会浪费带宽,服务器,防火墙和身份验证器资源。

所以我试图设计一些比自我造成的DoS攻击更好的东西。

我认为让服务器向客户端发送soap消息(推送)是不切实际的,因为这需要在客户端配置太多配置。但我认为还有其他我不了解的选择。如:

1)客户端是否有办法通过Soap 1.1发出GetMessageCount()请求,并获得响应,然后或许“保持在线”大概5-10分钟以获得额外的响应案例新数据到了吗?即服务器显示“0”,然后一分钟后响应一些SQL触发器(服务器是Sql Server上的C#,顺便说一句),知道该客户端仍然“在线”并发送更新的消息计数为“5” “?

2)是否有一些其他协议可以用来“ping”客户端,使用从他们上一次GetMessageCount()请求收集的信息?

3)我甚至都不知道。我想我正在寻找一些魔术协议,其中客户端可以发送一个GetMessageCount()请求,其中包括“哦顺便说一句,如果答案在下一个小时内发生变化,请在此地址ping我... ”

此外,我假设任何这些“保持线路开放”方案都会严重影响服务器规模,因为它需要同时保持数千个连接打开。我认为这也可能会影响防火墙。

那里有什么东西吗?还是我几乎坚持投票?

TIA,
克里斯

更新4/30/2010:
已经证明拥有7秒通知既不容易也不便宜,特别是在没有超出HTTPS / SOAP /防火墙的企业标准的情况下,我们可能会推出一个两阶段的解决方案。 Phase1将让客户端轮询“按需”,GetMessageCount通过SOAP执行,这里没什么特别的。将有一个“刷新”按钮来提取新数据(这在这里是合理的,因为用户通常有理由怀疑新数据已准备就绪,即他们只是改变了在线系统中的结构颜色,因此他们知道点击在查看桌面上的运输清单之前刷新,现在他们看到描述中的颜色。)(这不是一个服装/时尚应用程序,但你明白了)。 使用此处讨论的技术,使用两个aps始终保持同步的概念,从主机推送的实时更新仍然在桌面上。但我希望它能够推出另一个版本,因为我们可以提供85%的功能,而无需这样做。但是,我希望我们能够做一个概念证明,并证明它可以工作。我会回来发布未来的更新。感谢大家的帮助。

10 个答案:

答案 0 :(得分:7)

考虑“播放”HTTP协议以获得您想要的内容,同时仍然能够遍历所有代理以及客户端可能拥有的NAT和防火墙。

让每个客户端以一种禁止任何类型缓存的方式对消息计数执行纯HTTP请求(例如:GET http://yourserver.org/getcount/nodeid/timeofday/sequence)。在HTTP服务器延迟的服务器端实现中,如果“count”与以前相同,则提供答案(即:没有新消息)。

我为一个在浏览器中运行的Ajax风格的应用程序做了这个,并且表现得有点像聊天应用程序,但是你的解决方案可以更快。我使用TIdHttp服务器实现了服务器端的东西,这让我实际上只是通过Sleep() - 在它的线程中延迟提供客户端内容的答案。从客户端来看,它看起来像服务器,有时候回答的速度很慢。

服务器端的伪代码:

function ClientHasMessages(ClientID:Integer; MaxWait:TDateTime):Boolean;
var MaxTime:TDateTime;
begin
  if ClientActuallyHasMessage(ClientID) then Result := True
  else
    begin
      MaxTime := Now + MaxWait;
      while Now < MaxTime do
      begin
        if ClientActuallyHasMessage(ClientID) then
          begin
            Result := True;
            Exit;
          end
        else
          Sleep(1000);
      end;
      Result := False; // TimeOut
    end;
end;

这段代码背后的想法:它运行在你自己的服务器上的一个线程中,它可以测试消息数量,大概是非常少的成本:

  • 等待时不会造成网络流量。
  • 睡觉时不使用CPU。
  • 它会让用户很快知道它的消息。
  • 它允许客户端控制等待的时间(客户端将增加服务器延迟答案的时间,直到它不再收到答案,然后退一步 - 这样协议适应客户端使用的任何有缺陷的NAT路由器。)
  • 您可以远离没有TCP / IP通信的长时间,并且仍能够立即提供答案。 30秒很容易完成,对于具有良好NAT路由器的客户端,它可以更长。

这是服务器上的要求,但我很想说它们是可行的:

  • 服务器的TCP / IP实现需要跟踪大量的并发连接(每个客户端都会始终激活HTTP请求)。我的Linux NAT机器现在正在跟踪15K连接,它基本上是空闲的,所以它可能会起作用。
  • 服务器将始终为每个客户端HTTP请求打开一个线程:同样,我正在使用的Server 2008“工作站”(感谢MSDN允许我做这些令人发指的事情)大约1500个线程处于活动状态,它也基本上处于空闲状态......
  • 根据您用于服务器端代码的技术,MEMORY可能是限制因素。

答案 1 :(得分:4)

我会看看kbmMW

我可能会使用类似于MS Exchange的方法 - 通过tcp / ip连接和身份验证,然后通过udp从服务器到客户端通知更新,然后客户端收到udp请求并通过tcp下载更新/ IP。

(至少我理解MS Exchange的工作原理)

答案 2 :(得分:3)

Delphi中多层开发的两大方面是组件4开发人员(Mark Robinson的答案中描述了他们的kbmMW产品)和他们的产品RemObjects SDK的RemObjects(他们有一个很好的例子,可能与您想要的类似:Push notifications for iPhone)。

在复杂的环境中,多播UDP可能不会削减它,但从开销角度看它是无与伦比的。

如果连接打开,它可以以双向方式使用(这也由.NET远程处理和WCF使用),但是有额外的开销。

您需要在保持连接(锁定资源)和创建新连接(花费时间和延迟)之间找到平衡。

- 的Jeroen

答案 3 :(得分:3)

您可以尝试拨打服务器并在服务器上等待一段时间(1分钟?),直到您有一些更新。这样您就不需要从服务器到客户端的连接,并且您几乎可以立即获得客户端的结果(如果您在1分钟内有更新,则结束等待呼叫)。这是一个相对容易和广泛(?)的网络应用程序(如Gmail:它有这样的背景连接:如果一个新的电子邮件到达你立即在你的收件箱中看到它!)。我使用这样的东西(RemObjects):

function TLoggingViewService.GetMessageOrWait: TLogMessageArray;
begin
  if (Session.Outputbuffer.Count > 0) or
     //or wait till new message (max 3s)
     Session.Outputbuffer.WaitForNewObject(3 * 1000)
  then
    //get all messages from list (without wait)
    Result := PeekMessage;
end;

否定点是:你保持连接打开一段相对较长的时间(如果由于wifi等连接丢失怎么办?)和高服务器“加载”(每个连接有一个线程,保持打开状态:如果你有很多客户端)你可以摆脱资源。)

我们在这里使用RemObjects,并使用TCP + Binmessage,它比SOAP + HTTP具有更低的开销,并且非常快!所以,如果你可以使用它,我真的可以推荐! (在你的情况下,你需要Remobjects for Delphi和RemObjects for .Net)。如果您需要连接第三方,只使用SOAP,如果您需要,则仅使用HTTP,因为互联网/防火墙。 SOAP很好但是开销和性能都很高。

您还可以使用以下组合:后台线程中的简单(RemObjects)TCP连接(具有低开销),轮询每个10秒并等待5秒以获取新数据。

答案 4 :(得分:3)

我已经在比10K客户端更大的系统上进行了性能测试,当你达到上述请求数/秒时,你很可能会遇到Connections / sec,并发打开连接,防火墙变慢等问题。 Torrent Tracker可能遇到的问题大致相同。

如果客户端只需要“询问是否有新的东西”,那么易于实现的最轻的协议就是UDP,下一个最轻的协议就是纯TCP,两者都使用Indy客户端。

协议本身实际上可以像向服务器发送“自[yyyy-mm-dd:mm:ss]之后的任何新内容”一样简单,并以1字节数回复(可能有256个答案)。

使用TCP,您可以保持“管道”打开几分钟,并且每隔x秒就可以发送“任何新的”消息。同样使用TCP,服务器可以在发生某些事情时将信息“推送”到管道(客户端),因为客户端正在定期检查管道中的数据。

答案 5 :(得分:2)

我会尝试在多个服务器之间尽可能多地分配负载。为此,我会做以下事情:

  1. 客户注册您的服务以获取通知。他们获得的会话ID在给定的时间内(15分钟)有效。
  2. 服务器将定期检查哪个注册客户端有传入消息,并生成此类客户端的列表(从技术上讲,我会在DMZ中将其推送到另一个数据库中)。
  3. 您运行了许多“推送通知”服务器,这些服务器遵循一个非常非常简单的协议:它们获得包含会话ID的URL查询,并使用简短的HTTP响应进行响应:带有(签名)的404或200要获取消息的SOAP服务器的URL。对于其他性能,您可以使用HTTP 1.1和持久连接。
  4. 客户端将根据需要经常汇集这些推送通知服务器。由于它们非常简单且严格只读,因此可以非常快速地回答查询,并且易于扩展。
  5. 如果客户端收到302响应,则可以连接到正确的SOAP服务器(如果需要,也可以使用它进行负载分配)并提取消息。
  6. 这里你必须小心安全。首先,我建议您不要为推送通知服务器使用HTTPS。相反,您可以使用客户端请求通知时交换的会话密钥来签署响应的内容。然后,客户负责验证答案。不要忘记,您不仅需要签署状态,还需要签署SOAP服务URL。

    这有点复杂,但通过将状态和实际消息流量分离,您可以更轻松地扩展解决方案。此外,在您真正想要交换数据之前,您不需要进行昂贵的SSL协商。

答案 6 :(得分:2)

我们为此使用RemObjects SDK“事件”,但这可能不适合您,因为

a:它只适用于RemObjects自己的二进制协议,而不是SOAP(即客户端必须包含RO代码)

b:基本上它是“保持线路开放”的方法。因此,10K客户端的可扩展性是一个潜在的问题。

我会尝试一些测试,看看实际上有10K套接字打开的开销。如果您只需要几个额外的服务器内存,这将是一个廉价的修复。并且因为套接字是从客户端打开的,所以不应该导致防火墙问题。防火墙可以做的最糟糕的事情是关闭套接字,因此当发生这种情况时,您的客户端需要重新打开它。

答案 7 :(得分:1)

只有当您的远程设备是iPhone时,iPhone的推送通知才有效。唯一的其他选择是保持连接打开(尽管大部分是空闲的)或从客户端轮询。

您可以通过简化调用来减少轮询的开销。使用简单的Web操作将最高的消息编号返回给客户端,并让客户端执行简单的HTTP GET以接收此编号。这减少了带宽量,并使其简单。如果客户端需要获取更新数据,则可以进行完整的肥皂调用。

答案 8 :(得分:1)

任何时候你有一台服务器和10,000多个客户端,你需要每隔几秒就进入更新,你会遇到问题。我会得到更多的服务器,并保持客户端连接在最初连接的客户端的后台线程上,然后等待通知从服务器进入内置的保持活动机制。

如果您尝试从服务器推送到非当前连接的客户端,那么如果您无法控制客户端环境,那么祝您好运。听起来像你被迫进入客户发起的联系。

答案 9 :(得分:0)

左边的一些东西。

为什么只需要获得一个标记表明更新已准备就绪需要进行身份验证?为什么不在认证防火墙之外安装一台机器......甚至在云端......除了处理那些“任何可用的”请求之外什么都不做。然后,如果有可用的东西,客户端会通过箍来获取真实数据。该请求服务器可以从真实服务器执行7秒的getcount。

我们现在谈的是非常少的数据,而且只需很少的设置时间就可以得到一个简单的'标志',甚至不算数。

它仍然有数千个请求,但与完全认证的请求相比,数千个请求的开销最小。