【发布时间】:2015-01-16 11:22:03
【问题描述】:
有一个讨厌的线程(客户端)正在等待来自远程设备(服务器)的事件。这些事件由专用网络通过 TCP 套接字接收(我必须分配一个静态 IP)。该操作不是阻塞操作,而是轮询 (select + recv)。对于某个操作,线程使用CURL 库启动与设备的FTP 传输。然后,有时,我们收到垃圾而不是下一个正常操作。该行为可以系统地在三台计算机中的两台上重现。如果设备直接通过网络端口连接,则其中一个可以工作,但如果通过网络 USB 适配器(允许 Internet 连接)则不能。另一方面,在这种情况下,适配器在另一台计算机上运行良好。 如果我们消除 FTP 传输,一切正常。 行为与使用的 CURL 版本和最后一个 7.40 相同。
我是这里的维护者,有一个旧的巨大项目,我几乎无法更改/重写,尤其是在这种情况下,这段代码显然工作了好几年(尽管有一些问题已发出信号)并且几乎测试前两个月。但是我必须解决这个问题,如果有必要,我会将操作从轮询更改为阻塞,例如。其他同事已经看到了代码,Application Verifier 没有检测到任何东西(不再),从 recv 接收到的缓冲区已经损坏,Wireshark 说我们正在接收正确的数据包 - 什么都没有!调试有点困难,因为这个巨大的“应用程序”没有调试设置,并且通过远程调试和一些“精心选择”的断点......错误的行为消失了。我尝试了大多数通常(过去获胜)的路径将近两周,其余的看起来也不太有希望 - 它们都需要时间:1)直接调试其中一台计算机(如果调试可复制并且在安装 VS 之后,从服务器获取整个代码)-我不知道还要尝试什么 2)编写“正确”代码以在单独的项目中执行此操作(已经以某种方式开始) 3)替代 llvm 构建(巨大的努力)。
感谢任何想法,我很乐意回应任何澄清要求。
编辑 我们在一个最小的测试程序中重现了这种情况。它通过 USB - 网络适配器发生在三台尝试过的两台计算机上。 我们通过 TCP 套接字从我们的设备获得两个命令。我们只读取第一个(1 个字节),使用 CURL 库进行 FTP 传输,然后我们读取另一个(7 个字节),但只有垃圾。如果我们用读取第二个命令来切换 FTP 调用,一切都很好,即使是在无限循环中。 Wireshark 显示数据(7 个字节)正确传输,因此很明显在 CURL FTP 传输期间发生了一些事情。但是它如何影响无关的套接字呢? 当前步骤是识别损坏我们套接字的 CURL 调用。
编辑 2
我们没有准确识别脏 CURL 调用,因为......它不是一个固定点。我们通过recv(..., MSG_PEEK) 和trace 进行识别,有时它可以在两个printf 指令之间,尽管它在同一个代码区域附近。恕我直言,这只是可能的,因为某些 CURL 连接调用产生了另一个线程(名为 _SockAsyncThread@4,显然是 Windows 内部使用的),它可能会改变我们套接字的堆栈。通过在某些地方添加Sleep(1500) ......它可以工作。与 64 位版本相同的“不工作”行为。虽然它从不与 CURL 一起使用,但通过将其替换为 FtpGetFile,它在循环中工作,但第一次调用的例外......它的驱动程序中有一些严重的问题(最新的,Windows 7 版本与 Vista 版本相同,顺便说一句)。在我看来,一种解决方法是首先阅读我们套接字上的通知,然后再处理它们。或者也许只需使用另一个线程来完成 FTP 工作。
【问题讨论】:
-
“另一方面,适配器工作得很好,在这种情况下,在另一台计算机上” - 可能值得检查与两者不同的计算机,例如网络驱动程序版本、杀毒软件、固件版本、防火墙配置等等。
-
当前过程是在我们识别出两种行为的计算机上比较日志(内部、Wireshark):它通过直接连接工作,而不是通过适配器。
-
@HarryJohnston Windows 防火墙可能是一个想法,即使我看不到它如何以这种方式影响行为。有趣的是,只有能用的电脑才有杀毒软件。
-
这听起来可能是 USB 适配器的网络驱动程序中的错误,甚至可能是 USB 总线驱动程序中的错误。驱动程序错误可能难以重现,问题未出现在第三台计算机上的原因可能看起来完全无关紧要。
-
@HarryJohnston 这是我们最新的想法,但我不相信套接字堆栈是由驱动程序管理的 - 我一直认为它是 WIndows 内核本身
标签: c++ sockets curl windows-7 visual-studio-2005