stlehmann / pyads

Python wrapper for TwinCAT ADS
MIT License
252 stars 93 forks source link

Multiple connection issues on Linux #331

Closed thunder-weasel closed 10 months ago

thunder-weasel commented 1 year ago

Multiple simultaneous instances of the following code works flawlessly on Windows:

plc_ip = '10.0.0.4'
plc_ams_id = '10.0.0.4.1.1'

our_port = pyads.open_port()

with pyads.Connection(plc_ams_id, pyads.PORT_TC3PLC1, plc_ip) as plc:
    plc.open()
    while True:
        print(plc.read_by_name('IO.tick1ms'))
        sleep(1)

A single instance works fine on Linux, however, when a second invocation is started the first instanced fails with:

53606
54609
55613
2022-10-20T10:26:30-0500 Info: connection closed by remote
2022-10-20T10:26:31-0500 Error: write frame failed with error: 32
Traceback (most recent call last):
  File "/mnt/store/vm/vshare/development/python3/beckhoff/./bare_test_01.py", line 15, in <module>
    print(plc.read_by_name('IO.tick1ms'))
  File "/home/jpiel/.local/lib/python3.10/site-packages/pyads/connection.py", line 540, in read_by_name
    return adsSyncReadByNameEx(
  File "/home/jpiel/.local/lib/python3.10/site-packages/pyads/pyads_ex.py", line 1154, in adsSyncReadByNameEx
    handle = adsGetHandle(port, address, data_name)
  File "/home/jpiel/.local/lib/python3.10/site-packages/pyads/pyads_ex.py", line 890, in adsGetHandle
    handle = adsSyncReadWriteReqEx2(
  File "/home/jpiel/.local/lib/python3.10/site-packages/pyads/pyads_ex.py", line 774, in adsSyncReadWriteReqEx2
    raise ADSError(err_code)
pyads.pyads_ex.ADSError: ADSError: Unknown Error (-1).

Any tips or ideas on what I'm doing wrong would be greatly appreciated.

thunder-weasel commented 1 year ago

Additional info: Above script runs fine with multiple instances on FreeBSD 13.1.

chrisbeardy commented 1 year ago

You're not the first person to bring this up, we believe it may be an issue with the underlying ADS library, so there is no easy fix in pyads. The way around it for now, if I remember correctly, is instead of running the program multiple times, is to run one program and create multiple instances of the connection class. This however I believe only works if you plan on accessing it from just the single PC, i believe if you have a connection from a linux pc, then open one from a windows pc for example, you would get this error still.

chrisbeardy commented 1 year ago

linked to #256 and #317

chrisbeardy commented 1 year ago

@thunder-weasel see #314 if tthat helps

thunder-weasel commented 1 year ago

"...i believe if you have a connection from a linux pc, then open one from a windows pc for example, you would get this error still." This is not the case. I just tested with 3 instances of the script running on a Windows virtual machine at the same time as 3 instances running on the FreeBSD PLC. A single instance still worked fine on Linux, but that instance dies when a second one is started. I did, also, start a 4th instance on both Windows and BSD and that had no effect on the Linux instance.

I tend to concur that this is probably a Linux issue. When I have a moment I'll repeat this exercise with C, if the results are the same I'll start working with my Beckhoff contacts to see if it can be resolved. Thank you much for the help and for your work on pyads!

thunder-weasel commented 1 year ago

Testing Notes and response I got from Beckhoff:

Two separate scripts to two different targets -> Works! Two separate scripts to the same target -> Only the last executing script works, the others fail at -1 error Single script connecting to two different targets -> Fails to connect on the second Open() command with ADSError: ROUTERERR_PORTALREADYINUSE I think it's a limitation of the PyADS on linux, primarily due to it using our adslib.so If pyAds was using our new .Net core sample, it would work. Alternatively, he could use our C# .Net Core API and get that functionality

Not sure if this is helpful, but this could describe why a Windows Client doesn’t have issues, it internally must be wrapping our Windows ADS dll…

Hopefully, the pyAds community can reach out and better explain what is happening under the hood.

metalika80 commented 1 year ago

I don't think using anything .Net on linux is an option. Anyways, the workaround is tricking ADS into thinking that each connection is to a different plc. It's explained in issue 49: https://github.com/Beckhoff/ADS/issues/49 It's not the most elegant solution, but it works. I have 5 connections to the same plc without problems.

chrisbeardy commented 1 year ago

@thunder-weasel could you please reclose this issue to help us manage the issue tracker. I don't believe this is an issue with pyads itself but rather Beckhoffs Linux ADS so best to close it here. Thanks.

fengyc commented 1 year ago

try this https://github.com/fengyc/ads-proxy