从阻塞套接字切换到非阻塞套接字有什么好处?

时间:2011-05-06 02:25:41

标签: delphi sockets components

我们有一个使用Delphi 2010和Indy 10开发的应用服务器。该服务器每秒接收超过50个请求,并且运行良好。但在某些情况下,在我看来,Indy非常模糊。它们的组件很好,但有时我发现自己只是为了理解一个简单的事情而深入研究源代码。 Indy缺乏良好的文档和良好的支持 我遇到的最后一件事对我来说是一个大问题:我必须检测客户端何时正常断开连接(例如,当客户端崩溃或关闭时。不告诉服务器它将断开连接)并且indy无法去做。如果我想要,我将不得不开发心跳,汇集或TCP保持活动等算法。我不想花更多的时间来做一个,至少我认为,组件工作。经过一些研究,我发现这不是Indy的错,但这是所有阻塞套接字组件的问题。

现在我真的想把服务器的核心改成另一个好的套件。我必须承认我倾向于使用非阻塞套接字。基于此,我有一些问题:

  • 从阻塞套接字切换到非阻塞套接字有什么好处?
  • 我是否能够检测到客户端断开连接(非正常)?
  • 哪个组件套件拥有最好的产品?我所说的最好的产品是:快速,良好的支持,良好的工具和易于实施。

我知道这一定是一个主观问题,但我真的希望听到你的意见。我的第一个问题是我最关心的问题。我不在乎我是否需要支付100,500,1000,10000美元,但我想要一个完整的解决方案。现在,我正在考虑Ip*works

修改

我觉得有些人不明白我想要什么。我不想创建自己的套接字。我已经使用插座很长时间了,我厌倦了它。真。

非阻塞套接字可以检测客户端断开连接。这是事实,它在整个互联网上都有很好的文档。非阻塞套接字始终检查套接字状态是否有新的传入数据,并且可以检测到套接字无效。这不是心跳算法。在客户端使用心跳算法,它会定期向服务器发送数据包(也称为保持活动状态)以告知它仍处于活动状态。

修改

我不是说清楚。也许是因为英语不是我的主要语言。 我并不是说可以在不尝试从套接字发送或接收数据的情况下检测掉线连接。我所说的是每个非阻塞套接字都可以这样做,因为它们不断尝试从套接字读取新的传入数据。为什么这么难理解?如果你们下载并运行ip *工程演示,特别是echoserver和echoclient(都使用TCP),你可以自己测试。我已经测试了它,它的工作方式与我预期的相同。即使您在非阻塞模式下使用旧的TCPSocketServer和TCPSocketClient,您也会看到我的意思。

6 个答案:

答案 0 :(得分:14)

“从阻塞套接字切换到非阻塞套接字会带来什么好处?我能否检测到客户端断开连接(非正常)?

这个问题只是我的两分钱 - 我不是套接字专家,但我确实对他们有很多经验。如果我弄错了,我相信有人会纠正我...... :-)

我认为,由于您使用每秒50个连接的阻塞套接字运行服务器,因此您可以使用线程机制来处理客户端请求。如果是这样,你就不会从非阻塞插座获得任何东西。相反 - 您必须根据主线程中从非阻塞套接字触发的事件将您的服务器逻辑更改为事件驱动,或者使用常量轮询来了解您的套接字最多。

非阻塞套接字无法检测到客户端断开连接而不通知阻塞套接字可以 - 它们没有心灵感应功能......客户端和服务器之间TCP / IP“对话”的性质是相同的 - 阻塞和非阻塞只是针对您的应用程序与执行“对话”的套接字连接的交互。

如果需要清除死连接,则需要在套接字上实现心跳或超时机制(我从未见过不支持超时的现代套接字实现)。

答案 1 :(得分:4)

  

从阻塞套接字切换到非阻塞套接字有什么好处?

提高速度,可用性和吞吐量(根据我的经验)。我有一个IndySockets客户端,每秒大约有15个请求,当我直接进入异步套接字时,吞吐量增加到每秒约90个请求(在同一台机器上)。在具有30 Mbit连接的数据中心的服务器上进行单独的基准测试时,我每秒可以获得超过300个请求。

  

我是否能够检测到客户端断开连接(非正常)?

这是我还没有尝试过的一件事,因为我的所有代码都在客户端。

  

哪个组件套件拥有最好的产品?我所说的最好的产品是:快速,良好的支持,良好的工具和易于实施。

你可以在几天内建立自己的套接字客户端,它可以非常强大和快速......比我见过的“现成的”大多数东西要快得多。请随意查看我的异步套接字客户端:http://codesprout.blogspot.com/2011/04/asynchronous-http-client.html

<强>更新
(Per Mikey的评论)

  

我要求你提供关于NBS如何提高吞吐量的通用技术解释,而不是正确设计的BS服务器。

让我们以高负载服务器为例:假设您的服务器在任何给定时间都应该处理1000个连接,使用阻塞套接字就必须创建1000个线程,即使它们大部分处于空闲状态,CPU仍然会花费大量时间进行上下文切换。随着客户端数量的增加,您将不得不增加线程数以便跟上并且CPU将不可避免地增加上下文切换。对于使用阻塞套接字建立的每个连接,您将产生生成新线程的开销,最终您将承担在线程之后清理的开销。当然,首先想到的是:为什么不使用ThreadPool,您可以重用线程并减少创建/清理线程的开销。

以下是在Windows上处理这个问题的方法(因此是.NET连接):确定你可以,但是你会注意到.NET ThreadPool的第一件事就是它有两种类型的线程,这不是巧合:用户线程和I / O完成端口线程。异步套接字使用IO完成端口,“允许单个线程在不同的句柄上执行同时的I / O操作,甚至在同一个句柄上同时执行读写操作。”(1)I / O完成端口线程专门设计用于以比您在ThreadPool中使用用户线程时更有效的方式处理I / O,除非wrote your own kernel-mode driver

“完成端口使用一些特殊的voodoo来确保只能同时运行特定数量的线程 - 如果一个线程在内核模式下阻塞,它将自动启动另一个线程。”(2

还有其他优点:“除了重叠套接字I / O的非阻塞优势之外,另一个优点是性能更好,因为在每个I / O的TCP堆栈缓冲区和用户缓冲区之间保存缓冲区副本呼叫。” (3

答案 2 :(得分:2)

我使用Indy和Synapse TCP库已经有好几年了,并且没有找到任何showstoppers。我在线程中使用库 - 客户端和服务器端,稳定性和性能不是问题。 (典型的服务器运行在同一系统上,每秒有六千条请求和响应消息以及更多信息。)

如果协议比简单的'发送字符串/接收字符串'更高级,则阻塞套接字非常有用。非阻塞套接字导致消息协议处理程序与套接字读/写逻辑的更高耦合,因此我很快就摆脱了非阻塞代码。

没有库可以克服TCP / IP协议关于检测连接丢失的限制。只有尝试读取或发送数据才能说明连接是否仍然存在。

答案 3 :(得分:2)

在Windows中,有第三个选项是重叠的I / O.非阻塞套接字是使用开发的Windows消息的模型,以避免单线程GUI应用程序在等待数据时被“阻止”。使用线程和重叠I / O可以更好地设计现代应用程序IMHO。

参见例如http://support.microsoft.com/kb/181611

答案 4 :(得分:2)

Aahhrrgghh - 能够始终检测到“掉线”连接的神话。如果您在具有客户端连接的计算机上打开电源,则服务器无法在不发送数据的情况下判断连接是否“已死”。这是通过TCP协议的设计。不要相信我的话 - 阅读这篇文章(Detection of Half-Open (Dropped) TCP/IP Socket Connections)。

答案 5 :(得分:1)

本文解释了阻止和非阻塞之间的主要区别:

Introduction to Indy, by Chad Z. Hower

  

阻止优点

     
      
  • 易于编程 - 阻止编程非常简单。所有用户代码都可以   存在于一个地方,在一个地方   顺序。
  •   
  • 易于移植到Unix - 由于Unix使用阻塞套接字,可移植代码   可以轻松写出来。 Indy使用这个   实现其单一来源的事实   溶液
  •   
  • 在线程中运作良好 - 由于阻塞套接字是顺序的   本质上是封装的   因此很容易在线程中使用。
  •   
     

阻止的弊端

     
      
  • 用户界面“冻结”客户端 - 阻止套接字调用不会   回到他们完成之前   他们的任务。进行此类调用时   在应用程序的主线程中,   应用程序无法处理   用户界面消息。这导致   用户界面“冻结”因为   更新,重绘和其他消息   阻止之前无法处理   socket调用将控制权返回给   应用程序消息处理循环。
  •   

他还写道:

  

阻止不是邪恶的

     

反复阻塞套接字   没有逮捕令。与之相反   流行的信念,阻塞插座   不是邪恶的。

an issue of all blocking sockets components他们无法检测到客户端断开连接。在该领域的非阻塞组件方面存在 no 技术优势。