Python 如何停止pymodbus异步ModbusTcpServer?
我想停止一个Python 如何停止pymodbus异步ModbusTcpServer?,python,python-3.x,twisted,reactor,pymodbus,Python,Python 3.x,Twisted,Reactor,Pymodbus,我想停止一个pymodbusasyncModbusTcpServer然后启动一个新服务器。因此,我尝试使用以下简化代码段,但出现了一个错误: from pymodbus.server.async import StartTcpServer, StopServer from pymodbus.device import ModbusDeviceIdentification from pymodbus.datastore import ModbusSequentialDataBlock from p
pymodbus
asyncModbusTcpServer
然后启动一个新服务器。因此,我尝试使用以下简化代码段,但出现了一个错误:
from pymodbus.server.async import StartTcpServer, StopServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from time import sleep
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
def main(name='Pymodbus'):
store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [17]*100))
context = ModbusServerContext(slaves=store, single=True)
identity = ModbusDeviceIdentification()
identity.VendorName = name
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'Pymodbus Server'
identity.ModelName = 'Pymodbus Server'
identity.MajorMinorRevision = '1.0'
StartTcpServer(
context,
identity=identity,
address=("localhost", 5020),
defer_reactor_run=True
)
sleep(3)
name += 'stuff'
StopServer()
sleep(3)
main(name) # Recursive
main()
输出:
输出:
INFO:pymodbus.server.async:在本地主机上启动Modbus TCP服务器:5020
调试:pymodbus.server.async:在主线程中运行
调试:pymodbus.server.async:在派生线程中运行
调试:pymodbus.server.async:从另一个线程停止服务器
信息:pymodbus.server.async:在本地主机上启动Modbus TCP服务器:5020
调试:pymodbus.server.async:在主线程中运行
回溯(最近一次呼叫最后一次):
文件“stack.py”,第41行,在
main()
文件“stack.py”,第39行,在main中
main()#递归
文件“stack.py”,第35行,在main中
延迟反应堆运行=错误
StartTcpServer中的文件“/usr/local/lib/python3.6/dist packages/pymodbus/server/async.py”,第257行
run(installSignalHandlers=\u是\u主线程()
文件“/usr/local/lib/python3.6/dist-packages/twisted/internet/base.py”,第1260行,正在运行
self.startRunning(installSignalHandlers=installSignalHandlers)
文件“/usr/local/lib/python3.6/dist-packages/twisted/internet/base.py”,第1240行,在startRunning中
反应器基础启动耳轴(自)
文件“/usr/local/lib/python3.6/dist-packages/twisted/internet/base.py”,第748行,在startRunning中
引发错误。ReactorNotRestartable()
twisted.internet.error.ReactorNotRestartable
在第一个示例中,TCP服务器没有运行,因为您将param defer_reactor_run设置为True,但您没有明确运行它。因此,当您尝试停止它时,它会失败,因为它尚未启动
在第二个示例中,您运行了它,但下次将使用main(name)调用递归调用它!所以,它失败了,因为它已经启动了!
下一个代码应该可以工作:
from pymodbus.server.async import StartTcpServer, StopServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from time import sleep
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
def main(name='Pymodbus'):
store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [17]*100))
context = ModbusServerContext(slaves=store, single=True)
identity = ModbusDeviceIdentification()
identity.VendorName = name
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'Pymodbus Server'
identity.ModelName = 'Pymodbus Server'
identity.MajorMinorRevision = '1.0'
StartTcpServer(
context,
identity=identity,
address=("localhost", 5020),
defer_reactor_run=False
)
sleep(3) # for the fun ?
# and do your stuff
StopServer()
main()
如果要推迟运行,必须调用:
from twisted.internet import reactor
StartTcpServer(context, identity=identity, address=("localhost", 5020),
defer_reactor_run=True)
reactor.run()
我找到了另一种解决方案,通过另一个Python代码停止并启动异步ModbusTcpServer,因为显然,我们无法重新启动
reactor
事件循环
这是
runner.py
代码:
import subprocess
python_version = '3'
path_to_run = './'
py_name = 'async_server.py'
def run():
args = [f"python{python_version}", f"{path_to_run}{py_name}"]
sub_process = subprocess.Popen(args, stdout=subprocess.PIPE)
output, error_ = sub_process.communicate()
if not error_:
print(output)
else:
print(error_)
run() # Recursively.
if __name__ == '__main__':
run()
这是
async_server.py
代码段:
from pymodbus.server.async import StartTcpServer, StopServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
import threading
import sys
import logging
FORMAT = ('%(asctime)-15s %(threadName)-15s'
' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)
def stop():
print('Process will be down.')
StopServer() # Stop server.
sys.exit(0) # Kill the server code.
def run_async_server():
store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [17] * 100))
slaves = {
0x01: store,
0x02: store,
0x03: store,
}
context = ModbusServerContext(slaves=slaves, single=False)
identity = ModbusDeviceIdentification()
identity.VendorName = 'Pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'Pymodbus Server'
identity.ModelName = 'Pymodbus Server'
identity.MajorMinorRevision = '1.5'
from twisted.internet import reactor
StartTcpServer(context, identity=identity, address=("localhost", 5020),
defer_reactor_run=True)
print('Start an async server.')
t = threading.Timer(5, stop)
t.daemon = True
t.start()
reactor.run()
print('Server was stopped.')
if __name__ == "__main__":
run_async_server()
输出:
您可以使用库文件夹中包含的示例:asynchronous-server.py 在python3.7中,async作为关键字包含,但在pymodbus 2.3.0中,pymodbus.server.async更改为pymodbus.server.asynchronous 我跟大家分享一个对我来说很好的例子: 如果您还有任何问题,请通过电子邮件给我写信:Danielsalazr@hotmail.com
#Este codigo funciona ingresando a la direccion esclavo 16 en decimal
#la Ip debe ser la misma que esta asignada en el dispositivo
#los datos se actualizan a patir del registro #15
#Aparentemente la direcion del esclavo no tiene importancia, debido a que
#al realizar la conexion desde el software QModMaster, el numero ingresado
#em el campo SlaveAddr, no afecta la posibilidad de conexion
'''
Pymodbus Server With Updating Thread
--------------------------------------------------------------------------
This is an example of having a background thread updating the
context while the server is operating. This can also be done with
a python thread::
from threading import Thread
thread = Thread(target=updating_writer, args=(context,))
thread.start()
'''
#---------------------------------------------------------------------------#
# import the modbus libraries we need
#---------------------------------------------------------------------------#
from pymodbus.server.asynchronous import StartTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer
#---------------------------------------------------------------------------#
# import the twisted libraries we need
#---------------------------------------------------------------------------#
from twisted.internet.task import LoopingCall
#---------------------------------------------------------------------------#
# configure the service logging
#---------------------------------------------------------------------------#
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
#---------------------------------------------------------------------------#
# define your callback process
#---------------------------------------------------------------------------#
def updating_writer(a):
''' A worker process that runs every so often and
updates live values of the context. It should be noted
that there is a race condition for the update.
:param arguments: The input arguments to the call
'''
log.debug("updating the context")
context = a[0]
register = 3
slave_id = 0x01
address = 0x10
values = context[slave_id].getValues(register, address, count=5)
#el valor count = 5 modifica los datos de los siguientes 5 registros
#continuos al registro especificado en la variable address = 0x10, 16 en decimal
values = [v + 1 for v in values]
log.debug("new values: " + str(values))
context[slave_id].setValues(register, address, values)
#---------------------------------------------------------------------------#
# initialize your data store
#---------------------------------------------------------------------------#
store = ModbusSlaveContext(
di = ModbusSequentialDataBlock(0, [17]*100),
co = ModbusSequentialDataBlock(0, [17]*100),
hr = ModbusSequentialDataBlock(0, [17]*100),
ir = ModbusSequentialDataBlock(0, [17]*100))
context = ModbusServerContext(slaves=store, single=True)
#ModbusSlaveContext.setValues("lol",hr,3,25)
#context = ModbusServerContext(slaves=store, single=True)
#---------------------------------------------------------------------------#
# initialize the server information
#---------------------------------------------------------------------------#
identity = ModbusDeviceIdentification()
identity.VendorName = 'pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'pymodbus Server'
identity.ModelName = 'pymodbus Server'
identity.MajorMinorRevision = '1.0'
#---------------------------------------------------------------------------#
# run the server you want
#---------------------------------------------------------------------------#
time = 1 # 5 seconds delay
loop = LoopingCall(f=updating_writer, a=(context,))
loop.start(time, now=False) # initially delay by time
StartTcpServer(context, identity= identity, address=("192.168.0.40", 502)) #here you need
#change the ip for the ip address of your device
哥伦比亚的问候在第二个示例中,我使用pymodbusmaybe中的内置
StopServer()
在5秒后通过另一个线程停止反应器,但与此同时,在计时器唤醒之前,您尝试重新启动已启动的服务器。是否尝试了此代码片段?此代码卡在StartTcpServe()
中,因为defer\u reactor\u run
为false。但是,我想停止并重新启动服务器它没有卡住,它运行一台服务器。。。。如果你想停止它,请终止任务。我更新了如何在延迟模式下运行它。我的问题很明显,这不是我的答案,谢谢你的回答。你好,Daniel,因为pymodbus库已经更新了,pymodbus.server.async
已在较新版本中转换为pymodbus.server.asynchronous
,我知道这一点(我的问题是一年前在pymodbus的早期版本中提出的)。然而,这不是我的问题。正如我在问题中提到的,问题是StopServer
而不是StartTcpServer
import subprocess
python_version = '3'
path_to_run = './'
py_name = 'async_server.py'
def run():
args = [f"python{python_version}", f"{path_to_run}{py_name}"]
sub_process = subprocess.Popen(args, stdout=subprocess.PIPE)
output, error_ = sub_process.communicate()
if not error_:
print(output)
else:
print(error_)
run() # Recursively.
if __name__ == '__main__':
run()
from pymodbus.server.async import StartTcpServer, StopServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
import threading
import sys
import logging
FORMAT = ('%(asctime)-15s %(threadName)-15s'
' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)
def stop():
print('Process will be down.')
StopServer() # Stop server.
sys.exit(0) # Kill the server code.
def run_async_server():
store = ModbusSlaveContext(hr=ModbusSequentialDataBlock(0, [17] * 100))
slaves = {
0x01: store,
0x02: store,
0x03: store,
}
context = ModbusServerContext(slaves=slaves, single=False)
identity = ModbusDeviceIdentification()
identity.VendorName = 'Pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'Pymodbus Server'
identity.ModelName = 'Pymodbus Server'
identity.MajorMinorRevision = '1.5'
from twisted.internet import reactor
StartTcpServer(context, identity=identity, address=("localhost", 5020),
defer_reactor_run=True)
print('Start an async server.')
t = threading.Timer(5, stop)
t.daemon = True
t.start()
reactor.run()
print('Server was stopped.')
if __name__ == "__main__":
run_async_server()
$ python3 runner.py
2019-01-24 12:45:05,126 MainThread INFO async :254 Starting Modbus TCP Server on localhost:5020
2019-01-24 12:45:10,129 Thread-1 DEBUG async :222 Running in spawned thread
2019-01-24 12:45:10,129 Thread-1 DEBUG async :332 Stopping Server from another thread
b'Start an async server.\nProcess will be down.\nServer was stopped.\n'
2019-01-24 12:45:13,389 MainThread INFO async :254 Starting Modbus TCP Server on localhost:5020
2019-01-24 12:45:18,392 Thread-1 DEBUG async :222 Running in spawned thread
2019-01-24 12:45:18,392 Thread-1 DEBUG async :332 Stopping Server from another thread
b'Start an async server.\nProcess will be down.\nServer was stopped.\n'
2019-01-24 12:45:21,653 MainThread INFO async :254 Starting Modbus TCP Server on localhost:5020
2019-01-24 12:45:26,656 Thread-1 DEBUG async :222 Running in spawned thread
2019-01-24 12:45:26,657 Thread-1 DEBUG async :332 Stopping Server from another thread
b'Start an async server.\nProcess will be down.\nServer was stopped.\n'
.
.
.
#Este codigo funciona ingresando a la direccion esclavo 16 en decimal
#la Ip debe ser la misma que esta asignada en el dispositivo
#los datos se actualizan a patir del registro #15
#Aparentemente la direcion del esclavo no tiene importancia, debido a que
#al realizar la conexion desde el software QModMaster, el numero ingresado
#em el campo SlaveAddr, no afecta la posibilidad de conexion
'''
Pymodbus Server With Updating Thread
--------------------------------------------------------------------------
This is an example of having a background thread updating the
context while the server is operating. This can also be done with
a python thread::
from threading import Thread
thread = Thread(target=updating_writer, args=(context,))
thread.start()
'''
#---------------------------------------------------------------------------#
# import the modbus libraries we need
#---------------------------------------------------------------------------#
from pymodbus.server.asynchronous import StartTcpServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer
#---------------------------------------------------------------------------#
# import the twisted libraries we need
#---------------------------------------------------------------------------#
from twisted.internet.task import LoopingCall
#---------------------------------------------------------------------------#
# configure the service logging
#---------------------------------------------------------------------------#
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
#---------------------------------------------------------------------------#
# define your callback process
#---------------------------------------------------------------------------#
def updating_writer(a):
''' A worker process that runs every so often and
updates live values of the context. It should be noted
that there is a race condition for the update.
:param arguments: The input arguments to the call
'''
log.debug("updating the context")
context = a[0]
register = 3
slave_id = 0x01
address = 0x10
values = context[slave_id].getValues(register, address, count=5)
#el valor count = 5 modifica los datos de los siguientes 5 registros
#continuos al registro especificado en la variable address = 0x10, 16 en decimal
values = [v + 1 for v in values]
log.debug("new values: " + str(values))
context[slave_id].setValues(register, address, values)
#---------------------------------------------------------------------------#
# initialize your data store
#---------------------------------------------------------------------------#
store = ModbusSlaveContext(
di = ModbusSequentialDataBlock(0, [17]*100),
co = ModbusSequentialDataBlock(0, [17]*100),
hr = ModbusSequentialDataBlock(0, [17]*100),
ir = ModbusSequentialDataBlock(0, [17]*100))
context = ModbusServerContext(slaves=store, single=True)
#ModbusSlaveContext.setValues("lol",hr,3,25)
#context = ModbusServerContext(slaves=store, single=True)
#---------------------------------------------------------------------------#
# initialize the server information
#---------------------------------------------------------------------------#
identity = ModbusDeviceIdentification()
identity.VendorName = 'pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
identity.ProductName = 'pymodbus Server'
identity.ModelName = 'pymodbus Server'
identity.MajorMinorRevision = '1.0'
#---------------------------------------------------------------------------#
# run the server you want
#---------------------------------------------------------------------------#
time = 1 # 5 seconds delay
loop = LoopingCall(f=updating_writer, a=(context,))
loop.start(time, now=False) # initially delay by time
StartTcpServer(context, identity= identity, address=("192.168.0.40", 502)) #here you need
#change the ip for the ip address of your device