【问题标题】:pymodbus + docker connection issuepymodbus + docker 连接问题
【发布时间】:2019-11-11 16:05:05
【问题描述】:

我是 docker 和 Modbus 的新手,我正在尝试使用 Modbus(准确地说是 pymodbus 工具包)编写自定义客户端/服务器应用程序,但我可能遇到了 docker 的一些问题。

我已经尝试过示例脚本 client , server

我使用的部分是:

服务器(码头化)

from pymodbus.server.sync import StartTcpServer
from pymodbus.server.sync import StartTlsServer
from pymodbus.server.sync import StartUdpServer
from pymodbus.server.sync import StartSerialServer

from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSparseDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext

from pymodbus.transaction import ModbusRtuFramer, ModbusBinaryFramer
# --------------------------------------------------------------------------- #
# configure the service logging
# --------------------------------------------------------------------------- #
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 run_server():
    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)

    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 = '2.3.0'


    StartTcpServer(context, identity=identity, address=("0.0.0.0", 5020))

if __name__ == "__main__":
    print("running")
    run_server()

而且我只修改了 IP 地址。我可以让它在 localhost 上运行,但是当我将服务器部分放在 Docker 容器中时,我无法与之通信。

我正在使用 docker-compose,.yml 如下:

version: '3.4'

services:
  server:
    build: ./server
    #network_mode: host
    expose:
      - 5020
    ports:
      - 5020:5020

客户

from pymodbus.client.sync import ModbusTcpClient as ModbusClient
# from pymodbus.client.sync import ModbusUdpClient as ModbusClient
# from pymodbus.client.sync import ModbusSerialClient as ModbusClient

# --------------------------------------------------------------------------- #
# configure the client logging
# --------------------------------------------------------------------------- #
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)

UNIT = 0x1


def run_sync_client():

    client = ModbusClient('127.0.0.1', port=5020)
    client.connect()

    log.debug("Reading Coils")
    rr = client.read_coils(1, 1, unit=UNIT)
    log.debug(rr)

    log.debug("Write to a Coil and read back")
    rq = client.write_coil(0, True, unit=UNIT)
    rr = client.read_coils(0, 1, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.bits[0] == True)          # test the expected value

    log.debug("Write to multiple coils and read back- test 1")
    rq = client.write_coils(1, [True]*8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    rr = client.read_coils(1, 21, unit=UNIT)
    assert(not rr.isError())     # test that we are not an error
    resp = [True]*21

    resp.extend([False]*3)
    assert(rr.bits == resp)         # test the expected value

    log.debug("Write to multiple coils and read back - test 2")
    rq = client.write_coils(1, [False]*8, unit=UNIT)
    rr = client.read_coils(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.bits == [False]*8)         # test the expected value

    log.debug("Read discrete inputs")
    rr = client.read_discrete_inputs(0, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error

    log.debug("Write to a holding register and read back")
    rq = client.write_register(1, 10, unit=UNIT)
    rr = client.read_holding_registers(1, 1, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.registers[0] == 10)       # test the expected value

    log.debug("Write to multiple holding registers and read back")
    rq = client.write_registers(1, [10]*8, unit=UNIT)
    rr = client.read_holding_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rr.registers == [10]*8)      # test the expected value

    log.debug("Read input registers")
    rr = client.read_input_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error

    arguments = {
        'read_address':    1,
        'read_count':      8,
        'write_address':   1,
        'write_registers': [20]*8,
    }
    log.debug("Read write registeres simulataneously")
    rq = client.readwrite_registers(unit=UNIT, **arguments)
    rr = client.read_holding_registers(1, 8, unit=UNIT)
    assert(not rq.isError())     # test that we are not an error
    assert(rq.registers == [20]*8)      # test the expected value
    assert(rr.registers == [20]*8)      # test the expected value

    client.close()


if __name__ == "__main__":
    run_sync_client()

Docker 镜像启动正常,但是当我尝试运行客户端脚本时,我得到一个断言错误,这与没有容器运行时的failed-to-connect 错误不同。

2019-11-11 16:57:36,456 MainThread      DEBUG    client         :83       Reading Coils
2019-11-11 16:57:36,456 MainThread      DEBUG    transaction    :115      Current transaction state - IDLE
2019-11-11 16:57:36,456 MainThread      DEBUG    transaction    :120      Running transaction 1
2019-11-11 16:57:36,457 MainThread      DEBUG    transaction    :219      SEND: 0x0 0x1 0x0 0x0 0x0 0x6 0x1 0x1 0x0 0x1 0x0 0x1
2019-11-11 16:57:36,457 MainThread      DEBUG    sync           :75       New Transaction state 'SENDING'
2019-11-11 16:57:36,457 MainThread      DEBUG    transaction    :228      Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
2019-11-11 16:57:41,460 MainThread      DEBUG    transaction    :238      Transaction failed. (Modbus Error: [Invalid Message] Incomplete message received, expected at least 8 bytes (0 received)) 
2019-11-11 16:57:41,460 MainThread      DEBUG    socket_framer  :147      Processing: 
2019-11-11 16:57:41,460 MainThread      DEBUG    transaction    :394      Getting transaction 1
2019-11-11 16:57:41,460 MainThread      DEBUG    transaction    :193      Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
2019-11-11 16:57:41,460 MainThread      DEBUG    client         :85       Modbus Error: [Input/Output] Modbus Error: [Invalid Message] Incomplete message received, expected at least 8 bytes (0 received)
2019-11-11 16:57:41,460 MainThread      DEBUG    client         :100      Write to a Coil and read back
2019-11-11 16:57:41,461 MainThread      DEBUG    transaction    :115      Current transaction state - TRANSACTION_COMPLETE
2019-11-11 16:57:41,461 MainThread      DEBUG    transaction    :120      Running transaction 2
2019-11-11 16:57:41,461 MainThread      DEBUG    transaction    :219      SEND: 0x0 0x2 0x0 0x0 0x0 0x6 0x1 0x5 0x0 0x0 0xff 0x0
2019-11-11 16:57:41,461 MainThread      DEBUG    sync           :75       New Transaction state 'SENDING'
2019-11-11 16:57:41,461 MainThread      DEBUG    transaction    :228      Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
2019-11-11 16:57:45,001 MainThread      DEBUG    transaction    :304      Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
2019-11-11 16:57:45,001 MainThread      DEBUG    transaction    :233      RECV: 
2019-11-11 16:57:45,001 MainThread      DEBUG    socket_framer  :147      Processing: 
2019-11-11 16:57:45,001 MainThread      DEBUG    transaction    :394      Getting transaction 2
2019-11-11 16:57:45,001 MainThread      DEBUG    transaction    :193      Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
2019-11-11 16:57:45,001 MainThread      DEBUG    transaction    :115      Current transaction state - TRANSACTION_COMPLETE
2019-11-11 16:57:45,001 MainThread      DEBUG    transaction    :120      Running transaction 3
2019-11-11 16:57:45,001 MainThread      DEBUG    transaction    :219      SEND: 0x0 0x3 0x0 0x0 0x0 0x6 0x1 0x1 0x0 0x0 0x0 0x1
2019-11-11 16:57:45,001 MainThread      DEBUG    sync           :75       New Transaction state 'SENDING'
2019-11-11 16:57:45,002 MainThread      DEBUG    transaction    :238      Transaction failed. ([Errno 32] Broken pipe) 
2019-11-11 16:57:45,002 MainThread      DEBUG    socket_framer  :147      Processing: 
2019-11-11 16:57:45,002 MainThread      DEBUG    transaction    :394      Getting transaction 3
2019-11-11 16:57:45,002 MainThread      DEBUG    transaction    :193      Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
Traceback (most recent call last):
  File "client.py", line 166, in <module>
    run_sync_client()
  File "client.py", line 103, in run_sync_client
    assert(not rq.isError())     # test that we are not an error
AssertionError

我还尝试让容器使用主机接口(使用network-mode: host),效果很好。因此,我相信我的容器的网络设置有一些错误。据我所知,docker 容器确实在指定端口上侦听,但我的脚本不是?

我很高兴知道我的错误在哪里以及如何调试这些东西,我试图在 tcpdump 和 docker network inspect 中找到一些东西,但我找不到任何相关的东西。

【问题讨论】:

  • 您可以尝试在客户端提供主机的IP地址而不是127•0•0•1,看看是否可行(不带network=host)
  • 试过了,我现在收到“连接拒绝”响应。

标签: docker docker-compose modbus docker-networking pymodbus


【解决方案1】:

好的,一段时间后我意识到,我正在从同一个构建重新部署 docker 容器 - 所以我对服务器脚本 IP 所做的任何更改实际上都没有进行,因为 docker 总是使用第一个构建。现在我明白了为什么我应该使用卷挂载而不是复制文件。

我已经重建了 docker 镜像,并将服务器 IP 设置为 0.0.0.0(监听所有 IP),并且它按预期工作。希望至少这将帮助某人节省一些时间。

【讨论】:

    【解决方案2】:

    首先,您不应该在客户端连接服务器时使用 localhost (127.0.0.1) IP,因为当您使用 dockerized 服务器时,它的 IP 不再是 localhost。所以你有两个选择:

    • 如果您为客户端和服务器使用相同的机器/主机,则必须使用 docker 容器 IP (How to get the docker container IP) 或主机 IP

    • 否则,您必须使用唯一的主机 IP。


    [注意]:

    • 您的 docker-compose 文件应如下所示:

      version: '3.4'
      
      services:
        server:
          build: ./server
          container_name: modbus_server
          network_mode: host
          ports:
            - 5020:5020
      

      不需要expose属性。

    • 1234563在上面选择modbus_server)而不是Modbus客户端的IP。

    【讨论】:

    • 感谢您的明确答复。这次是我的“thinko”,因为我没有重建 docker 容器,但 localhost IP 也可能是个问题。我的朋友和我一起看了,我们修复了很多这些错误,事实上,现在我有一个功能强大的 Modbus 服务器,它甚至可以管理我的树莓的物理状态。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    • 2020-04-17
    相关资源
    最近更新 更多