【问题标题】:Socket Read In Multi-Threaded Application Returns Zero Bytes or EINTR (104)多线程应用程序中的套接字读取返回零字节或 EINTR (104)
【发布时间】:2010-04-06 04:30:26
【问题描述】:

我现在是一名 C 编码员 - 既不是新手也不是专家。现在,我在 PPC Linux 上使用 C 语言有一个特定的守护程序应用程序。我使用 PHP 的 socket_connect 作为客户端在本地连接到该服务。服务器使用 epoll 通过 Unix 套接字多路复用连接。使用 strstr() 解析用户提交的字符串以查找某些字符/单词,如果找到,则同时生成 4 个可连接线程到不同的网站。我使用套接字、连接、写入和读取,通过 TCP 在每个线程的端口 80 上与所述网络服务器进行交互。所有连接和写入似乎都是成功的。然而,对网络服务器套接字的读取失败,其中一个 (A) 所有 3 个线程似乎都挂起,只有一个线程返回 -1 并且 errno 设置为 104。响应线程需要大约 10 分钟 - 一个永恒的时间:-(。*我在某处读到 104(是 EINTR?),在网络上下文中表明...'连接已被对等方重置';或(B)来自 3 个线程的 0 个字节,并且 4 个线程中只有 1 个实际上返回一些数据。套接字读/写不是线程安全的吗?我使用线程安全(和可重入)的 libc 函数,例如 strtok_r、gethostbyname_r 等。

*我怀疑上述虚拟主机实际上是在重置连接,因为当我运行单线程独立运行(其他所有条件相同)时,所有事情都运行良好,但当然是串联而不是并行。

还有第二个问题(哎呀),我无法回信给连接到我的 epoll-ed Unix 套接字的客户端。我的守护程序应用程序将永远挂起并占用 CPU > 100%。然而,没有任何东西写给客户端。确定客户端(一个非常典型的 PHP 套接字应用程序)在发生这种情况时没有关闭连接 - 也没有检测到错误。有什么想法吗?

即使使用 Valgrind、GDB 或大量日志记录,我也无法弄清楚有什么问题。请在力所能及的地方提供帮助。

【问题讨论】:

  • 尝试在strace 下运行您的程序以获取有关正在发生的事情的更多信息。您也可以尝试使用 wireshark 来查看通过网络发送和接收的内容。
  • errno 104 是 ECONNRESET(由对等方重置连接),而不是 EINTR。

标签: sockets epoll multithreading eintr


【解决方案1】:

是的,读/写是线程安全的。但是,如果您正在使用 gethostbyname() 和 getservbyname(),请注意它们 - 它们返回指向静态数据的指针,并且可能不是线程安全的。

errno 104 是 ECONNREFUSED(不是 EINTR)。使用 strerror 或 perror 获取特定 errno 代码的文本错误消息(例如“对等连接重置”)。

找出问题所在的最佳方法通常是进行非常详细的日志记录 - 记录每个操作的结果,以及连接到的 IP 地址/端口、读取/写入的字节数、线程 ID 等详细信息,等等。当然,请确保您的日志记录代码是线程安全的 :-)

【讨论】:

  • 感谢您提供有用的建议。我确认(正如我之前提到的)我使用线程安全和可重入版本 gethostbyname_r、strtok_r 等。此外,我已经完成了所有可能的日志记录,以实际确定我看到代码死去的确切位置 - 在阅读时!不幸的是,我不能要求“读取”来注销它的内部,我只能等待接收它的输出和错误代码。
【解决方案2】:

10 分钟后获得 ECONNRESET 听起来像是连接超时的结果。网络服务器未发送数据或您的应用未接收数据。

要测试前者,请将 Wireshark 之类的程序连接到本地环回设备,并查找进出您正在使用的端口的流量。

对于后面的内容,请查看 epoll() 手册页。他们提到了使用边缘触发事件可能导致锁定的场景,因为缓冲区中仍有数据,但没有新数据进入,因此不会触发新事件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-14
    • 2010-09-30
    • 2015-07-12
    • 2017-12-12
    • 2015-03-18
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多