Python Modbus TCP客户端关闭连接,因为我的服务器实现出现意外响应

Python Modbus TCP客户端关闭连接,因为我的服务器实现出现意外响应,python,tcp,modbus,Python,Tcp,Modbus,我用Python实现了一个基于TCP的Modbus作为服务器软件。应用程序是多线程的,并且严重依赖于标准libs。我在管理服务器端的连接时遇到问题。 同时,我作为Modbus over TCP作为客户端的实现工作得很好 实现描述 服务器是多线程的,一个线程管理SOCK_流套接字以接收数据 框架 出于效率原因,使用select 信号量用于在发送或接收时防止对套接字资源的并发访问 Modbus上层的封装是通过发送和接收方法透明地完成的,不管怎样,只需构建一个具有正确标头和有效负载的帧 另一个线程运

我用Python实现了一个基于TCP的Modbus作为服务器软件。应用程序是多线程的,并且严重依赖于标准libs。我在管理服务器端的连接时遇到问题。 同时,我作为Modbus over TCP作为客户端的实现工作得很好

实现描述
  • 服务器是多线程的,一个线程管理SOCK_流套接字以接收数据 框架
  • 出于效率原因,使用select
  • 信号量用于在发送或接收时防止对套接字资源的并发访问
  • Modbus上层的封装是通过发送和接收方法透明地完成的,不管怎样,只需构建一个具有正确标头和有效负载的帧
  • 另一个线程运行,在它内部调用Modbus发送和接收方法
TCP上下文 TCP已启动并正在运行,绑定到端口,最大客户端集并正在侦听

wireshark下的跟踪显示:

  • 客户:SYN
  • 我的应用服务器:SYN,ACK
  • 客户:ACK
在服务器端,按照预期创建了一个全新的套接字,并绑定到客户端套接字

到目前为止,一切都很好。

Modbus上下文
  • 客户端:发送Modbus帧,TCP标志=0x18,即确认+推送
  • 我的应用服务器:不等待并发送单个空TCP确认帧
  • 客户端:等待带有tcp ack标志的modbus帧。因此,将其视为错误并要求关闭连接
因此,由于客户端的套接字正在关闭或已经关闭,我的服务器软件无法在之后发送任何实际响应

我的问题
  • 我收到主线程需要处理的modbus帧(服务器端)
  • 处理需要几毫秒,同时通过我的服务器套接字发送一个TCP ACK帧,而我希望它不发送任何东西
你知道如何管理ACK行为吗?我读过关于naggle算法的东西,但它似乎不在这里的问题范围之内。。。 我不确定setsockopt方法的任何选项是否也能解决我的问题,但我可能弄错了

如果你有任何建议,我很感兴趣。。。
我希望我足够清楚。

所有TCP数据包都必须包含有效负载,这似乎是一个奇怪的要求,因为这非常难以控制,除非您与TCP堆栈集成。如果确实是因为ACK没有Modbus有效负载而导致客户端崩溃,我认为您可以从python中做的唯一事情就是尝试禁用TCP_QUICKACK套接字选项,以便TCP在发送ACK之前等待500毫秒。这显然不会在所有情况下都起作用(或者如果代码创建响应的时间大于500毫秒,则可能根本不起作用),但我不知道还有其他使用python中socket API的选项


此答案告诉您如何禁用它:。应该很容易找到如何从中启用它。注意,您需要在收到数据后不断地重新启用它

我不熟悉Modbus,但是如果您正在用Python编写TCP内容,发送/接收ACK对您的代码不应该是完全透明的吗?在PythonTCP客户机中,您如何知道在没有有效负载的情况下收到了ACK?recv()应该在有实际数据时返回。我不明白为什么发送一个空的ACK是不好的,并且会导致一个错误。在任何情况下,您都可以尝试使用延迟确认:TCP_QUICKACK套接字选项。您是对的,我不想直接管理TCP堆栈,我希望它对我来说是透明的。然而,我在wireshark(网络嗅探工具)上看到,我的套接字在没有有效负载的情况下自己发送TCP ACK。而我的应用程序仍然处于适当的处理过程中。发送一个空的TCP ACK似乎被Modbus客户端当作一个错误的例子,这就是为什么我会阻止底层TCP栈发送任何类型的TCP ACK,因为一些TimeSTCP ACK是TCP可靠性特征的一个组成部分。如果阻止发送,客户端网络堆栈将重新发送最后一个数据包。此外,Modbus应该位于TCP之上,这意味着它通常不知道ACK数据包之类的事情。如果客户端因为收到ACK而崩溃,则表明它做错了。感谢您的回答,不幸的是,服务器正在windows操作系统上运行。无论如何,这个参数在注册表中似乎是可调的。。。我要试一试。