1

我编写了一个多线程 Socket Server 应用程序,它接受超过 1000 个并发连接。最近我们遇到了应用程序崩溃;分析转储文件后得知应用程序由于堆损坏而崩溃。我发现以下链接中讨论了相同的问题。

.NET 没有可靠的异步套接字通信? http://support.microsoft.com/kb/947862

并且讨论还提出了 3 个解决方案。

  1. 网络应用程序应该对其发布的未完成异步 IO的数量有一个上限。

  2. 使用微软 CCR

  3. 使用 TPL

由于时间因素,我想坚持#1,但我不清楚如何实现这一点。有人可以给出一个好的起点吗?

还有没有人使用 Async 和 TPL 来解决这个问题?

4

2 回答 2

1

您的意思是比我在您提到的答案中链接到的博客帖子更好的起点?

问题是这样的:

  • 在异步写入期间使用的内存和其他每次操作资源通常“正在使用”,直到远程对等方的 TCP 堆栈确认数据并且本地堆栈可以完成您的异步写入操作以告诉您可以重用缓冲区。
  • 本地对等点无法控制这一点,因为它完全取决于远程对等点从其套接字读取数据的速度以及两个对等点之间的链路拥塞。

由于上述原因,您需要对您在任何时候未完成的异步写入量有一个硬性限制。您可以通过在发出异步写入之前增加一个计数器并在完成处理程序中减少它来跟踪这一点。

一旦你达到这个限制,你会做什么取决于你。在原始文章中,我倾向于将要写入的数据放入队列中。然后,当写入完成时,此队列可用作数据源。一旦队列为空,您可以再次正常发送。当然,这只是解决了问题——您仍然拥有由远程对等方控制的内存资源(排队数据),但您也没有使用其他操作系统资源(非分页池、I/O 页面锁定限制、 ETC)。

当您达到限制时,您可以简单地停止您的对等发送 - 现在您在异步 API 上构建的 API 需要从以前一直使用的发送返回“目前无法发送,稍后再试” “工作”。

如果你这样做,我也会认真考虑通过在一个连续块中分配一大块缓冲区并从池中使用它们来避免固定内存问题。

于 2013-11-14T13:39:30.750 回答
0

首先,这是一篇非常古老的知识库文章。你怎么确定你有那个特殊的问题?然后,正如 Hans Passant 在 SO question 中回答的那样,如果你编写了糟糕的异步代码,它咬你一口。如果你不关心你的资源(内存缓冲区就是资源),并发程序面临内存错误

使用原始线程编写好的并发代码非常困难,TPL 确实使它更容易,但它不会修复你已经存在的错误。事实上,除非您确定您当前的问题,否则您很可能会将它们转移到使用 TPL 的版本。

在不知道导致您的应用程序崩溃的具体问题的情况下,我只能提出一些建议:

  1. 使用BufferManager重用内存缓冲区而不是分配新的缓冲区。
  2. 使用队列来存储请求并异步处理它们,而不是为每个请求启动一个新线程。

您还可以使用其他技术,具体取决于您正在构建的应用程序的类型。例如,您可以使用 TPL DataFlow 以独立步骤中断处理。

至于 CCR,在 Robotics Studio 之外使用它并没有多大意义。TPL 包含编写并发应用程序所需的大部分相关功能。

于 2013-11-14T10:06:41.513 回答