【问题标题】:Write to the client returns EWOULDBLOCK when server is slow当服务器速度慢时,写入客户端返回 EWOULDBLOCK
【发布时间】:2013-04-30 00:04:30
【问题描述】:

我正在尝试在特定时间间隔后在套接字中写入一些数据。我有两个线程,一个线程维护 TCP 连接,另一个线程生成数据。

数据生成 therad 生成数据,并将其写入共享内存。服务器线程从共享内存中读取数据,并将其发送给客户端。

但是,当数据生成线程变慢时,当涉及大量计算时,服务器线程在尝试写入客户端时会收到 EWOULDBLOCK 错误。但是,令人惊讶的是,从客户端来看,并没有这样的错误。

如果我没记错的话,当服务器比客户端快并且套接字缓冲区在再次写入之前未完全读取时,将返回 EWOULDBLOCK 错误。但是,这里的情况完全相反。

可能是因为服务器therad一直处于休眠状态,直到数据生成线程完成(数据线程具有更高的优先级)。

有人能解释一下这里可能发生的事情吗?

【问题讨论】:

    标签: c++ sockets tcp


    【解决方案1】:

    当您使用非阻塞套接字并且内核的传出数据缓冲区中没有足够的空间供该套接字保存您要发送的任何数据时,将返回 EWOULDBLOCK。如果客户端读取速度太慢,可能会发生这种情况,但如果服务器尝试一次发送大量数据,也可能发生(即使客户端速度很快);例如,如果您的计算线程花了很长时间计算数据,然后在计算结束时突然一次传递了超过 300,000 字节的数据,您的服务器线程可能会这样做:

    1. 看到共享内存区域中有一些数据可用,是时候开始发送了!
    2. 使用 len=300000 调用 send()。 send() 会吸收尽可能多的数据,因为它可以放入内核的输出套接字数据缓冲区(例如 131,072 字节)并返回 131072 以指示它已完成的操作。
    3. 现在您的服务器线程发现它还有 168928 字节的数据要发送,所以它再次调用 send() 并设置 len=168928。此时,内核的输出套接字数据缓冲区仍然完全充满(因为还没有机会发送任何数据包),所以 send() 返回 EWOULDBLOCK。

    一般来说,只要您使用非阻塞套接字,EWOULDBLOCK 就是您的代码需要处理的东西。我通常的处理方式是:

    1. 在 select()(或 poll() 等)中等待,直到套接字返回准备好写入
    2. 当 select()/poll() 指示套接字已准备好写入时,在套接字上调用 send() 直到您发送了所有可用数据,或者直到 send() 返回 EWOULDBLOCK(无论哪个首先)。
    3. 如果您在第 2 步中获得了 EWOULDBLOCK,请转到第 1 步。

    这样,您的发送线程将始终尽可能快地将传出数据提供给内核,但不会更快 - 即您不会浪费任何 CPU 进行忙循环,但您也不会浪费时间在流程中插入任何不必要的延迟。

    【讨论】:

    • 嗨 Jeremy,非常感谢..我会尝试读取共享内存中的数据量,看看这是否真的是问题..
    猜你喜欢
    • 1970-01-01
    • 2021-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多