代码之家  ›  专栏  ›  技术社区  ›  Benyamin Jafari

如何克服ModbustCPServer中的“地址已在使用中”,重新启动应用程序?

  •  1
  • Benyamin Jafari  · 技术社区  · 6 年前

    说明和代码:

    我正在使用同步ModbustCpserver pymodbus 创建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() 连接在客户端以解决此问题,但我希望有一个稳定的服务器。


    问题:

    有内置的方法来克服这个问题吗?我知道这个论点( 插座.so )在异步ModbustCpserver中(in async.py )但同步modbustcpserver中没有( sync.py )


    [ 注释 ]

    版本

    • 蟒蛇:3.6
    • 操作系统:Ubuntu 16.04
    • Pymodbus:1.5.2
    • Modbus硬件(如果使用):否

    pymodbus特定

    • 服务器:TCP-同步
    • 客户端:TCP-同步
    1 回复  |  直到 6 年前
        1
  •  1
  •   Nihal Saranga    6 年前

    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)
    

    socketserver here


    updating_server.py

    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
    import signal
    import time
    
    logging.basicConfig()
    log = logging.getLogger()
    log.setLevel(logging.DEBUG)
    
    SERVER = None
    THREADED_SERVER = None
    LOOP = None
    
    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)
    
    class ThreadedModbusServer(threading.Thread):
        def __init__(self, server):
            super(ThreadedModbusServer, self).__init__(name="ModbusServerThread")
            self._server = server
            self.daemon = True
    
        def run(self):
            self._server.serve_forever()
    
        def stop(self):
            if isinstance(self._server, ModbusTcpServer):
                self._server.shutdown()
            else:
                if self._server.socket:
                    self._server.server_close()
    
    
    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------------")
        time.sleep(0.1)
    
    def run_server():
        global SERVER, THREADED_SERVER, LOOP
        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 = ReusableModbusTcpServer(context,
                                 identity=identity,
                                 address=('0.0.0.0', 5021))  # Problem cause.
        THREADED_SERVER = ThreadedModbusServer(SERVER)
        THREADED_SERVER.start()
        LOOP = LoopingCall(f=update_values, a=SERVER)
        LOOP.start(interval, now=True)
        reactor.run()
    
    def signal_handler(signal, frame):
        global THREADED_SERVER, LOOP
        log.warning("You pressed Ctrl+C! ."
                  "If the program does not quit, Try pressing the CTRL+C again!!!")
        if THREADED_SERVER:
            THREADED_SERVER.stop()
            THREADED_SERVER = None
        if LOOP:
            LOOP.stop()
            LOOP = None
        if reactor.running:
            reactor.stop()
        else:
            exit(1)
    
    if __name__ == "__main__":
        signal.signal(signal.SIGINT, signal_handler)
        run_server()