我有这种情况...... 客户端启动的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%的功能,而无需这样做。但是,我希望我们能够做一个概念证明,并证明它可以工作。我会回来发布未来的更新。感谢大家的帮助。
答案 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;
这段代码背后的想法:它运行在你自己的服务器上的一个线程中,它可以测试消息数量,大概是非常少的成本:
这是服务器上的要求,但我很想说它们是可行的:
答案 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)
我会尝试在多个服务器之间尽可能多地分配负载。为此,我会做以下事情:
这里你必须小心安全。首先,我建议您不要为推送通知服务器使用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。
我们现在谈的是非常少的数据,而且只需很少的设置时间就可以得到一个简单的'标志',甚至不算数。
它仍然有数千个请求,但与完全认证的请求相比,数千个请求的开销最小。