如何克服ModbusTcpServer中“地址已在使用”的问题?

2024-03-28 08:11:47 发布

您现在位置:Python中文网/ 问答频道 /正文

说明和代码:

我使用带有pymodbus库的同步ModbusTcpServer创建一个Modbus从/服务器,代码如下:

from pymodbus.server.sync import StartTcpServer, ModbusTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from twisted.internet.task import LoopingCall
from twisted.internet import reactor
import threading
import logging

logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)

def run_server():
    block1 = ModbusSequentialDataBlock(0x00, [717] * 0x0F)
    block2 = ModbusSequentialDataBlock(0x10, [323] * 0x1F)
    store2 = ModbusSlaveContext(hr=block1, ir=block2)

    slaves = {
        0x01: store2,
    }

    context = ModbusServerContext(slaves=slaves, single=False)

    identity = ModbusDeviceIdentification()
    identity.VendorName = 'Pymodbus'
    identity.ProductCode = 'PM'
    identity.VendorUrl = 'http://github.com/riptideio/pymodbus/'
    identity.ProductName = 'Pymodbus Server'
    identity.ModelName = 'Pymodbus Server'
    identity.MajorMinorRevision = '1.0'

    interval = 2
    server = ModbusTcpServer(context,
                             identity=identity,
                             address=('0.0.0.0', 5021))  # Problem cause.
    thread_ = threading.Thread(target=server.serve_forever, daemon=True)
    thread_.start()
    loop = LoopingCall(f=update_values, a=server)
    loop.start(interval, now=True)
    reactor.run()


def update_values(a):
    print("-----------START-----------")
    rfuncode = 3
    wfuncode = 16
    slave_id = 0x01
    address = 0x00
    context_ = a.context[slave_id]
    values = context_.getValues(rfuncode, address, count=32)
    print(values)
    values = [val+1 for val in values]
    context_.setValues(wfuncode, address, values)
    print("------------END------------")


if __name__ == "__main__":
    run_server()

当客户端应用程序连接到此服务器时,当我关闭此代码(使用Ctrl+C)并再次运行时遇到此错误:

OSError: [Errno 98] Address already in use 我知道在创建套接字时,我们可以使用socket.SO_REUSEADDR来克服这个问题。在

另外,我可以在客户端建立.close()连接来解决这个问题,但是我想要一个稳定的服务器。在


问题:

有没有一种内在的方法可以克服这个问题?我在异步ModbusTcpServer中找到了这个参数(socket.SO_REUSEADDR),但在同步ModbusTcpServer(sync.py)中没有。在


[注意]:

版本

  • Python:3.6.5
  • 操作系统:Ubuntu 16.04
  • Pymodbus:1.5.2
  • Modbus硬件(如使用):否

Pymodbus特定

  • 服务器:tcp-同步
  • 客户端:tcp-同步

Tags: run代码fromimport服务器serveraddresslogging
1条回答
网友
1楼 · 发布于 2024-03-28 08:11:47

ModbusTcpServer派生自socketserver.ThreadingTCPServer。要重用该地址,必须显式重写类变量allow_resuse_address。在

class ReusableModbusTcpServer(ModbusTcpServer):

    def __init__(self, context, framer=None, identity=None,
                 address=None, handler=None, **kwargs):
        self.allow_reuse_address = True
        ModbusTcpServer.__init__(self, context, framer, identity, address, handler, **kwargs)

有关更多信息,请参阅socketserverhere的源代码


[更新]:

你在混合线程和反应器。twisted有自己的信号处理程序,这可能是服务器没有按预期退出的原因。顺便问一下,你检查过updating_server.py的例子了吗?你所做的和异步服务器很相似。默认情况下,它可以重用地址,并处理优雅的终止。在

但万一你还想用你的代码。这里有一个丑陋的黑客来处理阻止程序。请注意,在某些情况下,您必须将Ctrl+C`保存两次,然后您将看到来自线程模块的一些难看的回溯。在

^{pr2}$

相关问题 更多 >