【问题标题】:Resolve Windows socket error WSAENOBUFS (10055)解决 Windows 套接字错误 WSAENOBUFS (10055)
【发布时间】:2017-11-07 12:38:45
【问题描述】:

我们的应用程序具有主动连接到客户的内部工厂网络并在发生检查事件时发送消息的功能。客户将其机器和应用程序的 IP 地址和端口号输入到我们的软件中。

我在阻塞模式下使用 TClientSocket,并为OnConnectOnError 事件提供了回调函数。假设上述功能已激活,当应用程序启动时,我在单独的线程中调用以下代码:

// Attempt active connection
try
    m_socketClient.Active := True;
except
end;

// Later...
// If `OnConnect` and socket is connected...send some data!
// If `OnError`...call `m_socketClient.Active := True;` again

当 IP + 端口有效时,该功能运行良好。但如果不是这样,在数千次错误(以及数小时甚至数天)之后,最终会发生 Windows 套接字错误 10055 (WSAENOBUFS) 并且应用程序崩溃。

this one from ServerFrameworkthis one from Microsoft 等各种文章都谈到了 exhausting the Windows non-paged pool 并提到 (1) 主动管理未完成的异步发送操作的数量和 (2) 释放用于 I/O 操作的数据缓冲区。

我的问题是如何实现这一点,分为三个方面:

A)我做错了什么导致内存泄漏?例如,OnError 处理程序中是否缺少一些清理代码?

B) 你如何监控 I/O 缓冲区以查看它们是否被耗尽?我已经使用Process Explorer 来确认我的应用程序是导致泄漏的原因,但理想情况下我需要一些编程方式来衡量这一点。

C) 除了重启应用之外,有没有办法让 Windows 清除或释放 I/O 操作数据缓冲区?

Delphi、C/C++、C# 中的代码示例。

【问题讨论】:

  • 你可能知道 TClientSocket 自 Delphi 6 以来已被弃用,现在是 16 年半前。如果这些组件没有正确清理手柄,我不会感到惊讶。其他写得很糟糕的 Delphi 组件(如 shell 组件)也已被弃用并在以后被删除。
  • 谢谢 Günther,其实我并不知道。需要刷新我使用的组件!经过一天的研究和测试,我想我已经发现了问题(这反映了我在使用这些 TCP/IP 组件方面的经验不足)......当套接字超时并触发 OnError 事件时,你应该致电m_socketClient.Socket.Close()。我正忙着完成我的调查,并会据此得出一个答案。
  • TClientSocket 可能已被弃用,但它是一个相当坚如磐石的组件。我从来没有遇到过任何内存/资源问题,而且我已经使用了很长时间。但我从未尝试在OnError 事件中设置Active := True。在那种情况下,我总是Close() 失败的套接字,然后让线程决定何时再次打开套接字。如果打开连接时出现错误,最好等待几秒钟再尝试再次打开连接。如果在读/写 I/O 过程中发生错误,则立即重新连接。
  • 谢谢雷米。同意,TClientSocket 非常好……我只是在出错后忽略了在套接字上调用Close()。每次停止使用套接字时(例如服务器断开连接时),是否必须调用Close()?我确信 Embarcadero 文档在某处清楚地说明了这一切,但我没有发现它。我们没有发现这一点,而是在开发中,因为它是一项高级功能,通常在连接系统上进行测试(或在非连接系统上仅测试几个小时)。羞于发现客户......但至少我已准备好发布修复:o)

标签: windows sockets delphi


【解决方案1】:

A) 资源泄漏的原因是编程错误。当OnError事件发生时,应调用Socket.Close()释放与socket相关的低级资源。

B) 内存泄漏未显示在进程的标准Working Set 内存使用中。需要监视属于您的进程的打开句柄,这可以通过GetProcessHandleCount 进行。请参阅 Delphi 中的this answer,它已经过测试并且运行良好。此answer in C++ 未经测试,但答案已被接受,因此应该可以使用。当然,你应该可以直接在 C++ 中使用GetProcessHandleCount

C) 经过大量研究,我必须得出结论,就像正常的内存泄漏一样,您不能只要求 Windows 在您之后“清理”!句柄资源已被您的应用程序泄漏,您必须找到并修复原因(参见上面的 A 和 B)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    • 2010-09-23
    • 2020-03-17
    • 2017-12-22
    • 1970-01-01
    • 2016-04-19
    相关资源
    最近更新 更多