frangoteam / FUXA

Web-based Process Visualization (SCADA/HMI/Dashboard) software
https://frangoteam.org
MIT License
2.74k stars 805 forks source link

[BUG] ModbusTCP client read/write Holding Registers sends TCP messages that do not comply with Modbus specifications. #1030

Open sunjichao1226 opened 9 months ago

sunjichao1226 commented 9 months ago

Describe the bug Create a ModbusTCP client under FUXA Server. When writing multiple Float32 points, FUXA will randomly encapsulate multiple Modbus messages into one TCP message, causing the ModbusTCP server to be unable to process it normally and causing unreliable communication. According to the Modbus specification, a separate Modbus message should be encapsulated in a TCP message, so that most ModbusTCP Server stations can establish normal communication.

To Reproduce Steps to reproduce the behavior:

  1. Create and start the ModbusTCP client under FUXA Server, configure the ModbusTCP server correctly, and create a communication point in the master station with the address Holding Registers, such as 40005, the data type is Float32, and a script is used to continuously write point values to achieve write point communication to the Modbus server.

Expected behavior

Screenshots modbus-server

Environment

unocelli commented 9 months ago

Hi, thanks for the report. I wonder if this is not a problem with the library used by FUXA modbus-serial. Have you try to enable 'Fragmented' image

sunjichao1226 commented 9 months ago

Thanks for your reply. I've tried enabling the 'Fragmented' option, but the same issue still occurs. I don't think Modbus-Serial should have similar problems because it only has a physical layer, a link layer, and an application layer. The ModbusTCP problem should lie in the network layer and the transport layer, and the one-to-many phenomenon occurs when the application layer data is encapsulated at the transport layer. Different Wireshark versions parse ModbusTCP differently, and different Modbus Servers do not respond to such requests differently, and other people should have different understandings of ModbusTCP frames. The best way is to encapsulate a Modbus request in an TCP packet without causing exceptions. The following is a screenshot of the network data of Version 4.2.0 under Windows.

ModbusTCP

rvbatista commented 9 months ago

Hello @sunjichao1226 Modbus-serial mentioned by @unocelli is the Modbus project used by FUXA to handle all types of Modbus requests. I already handled some issues on Modbus part of FUXA and as @unocelli, I think that this is a bug on Modbus-serial project.

sunjichao1226 commented 9 months ago

Hello @rvbatista , Thanks for your reply. I will try the following Modbus-serial project and contact @unocelli to see if this problem can be solved.I will report back if there is any news.

rvbatista commented 9 months ago

@sunjichao1226 I believe that this is the repository of the Modbus-serial project. https://github.com/yaacov/node-modbus-serial

I took a quick look over the issues and was not able to find anything related, but I think that It's possible to avoid this issue in FUXA, but it's better to solve it in Modbus-serial.

What is the frequency of yours request?

I saw that there are one read and one write in the Ethernet frame, it's always in this way? There is the FC 23 to read and write at the same time, but Modbus-serial doesn't implement it.

sunjichao1226 commented 9 months ago

Hello @rvbatista , the following is a screenshot of the data we write to multiple registers. Generally, the same address register will be read before or after writing the register. This is in line with Modbus convention. In the figure, the Modbus client write cycle is 500ms. FUXA processing generally writes the register separately for each Float32 type point item, and then reads back all addresses within its address range together. However, ModbusTCP data packets will be packaged in an undetermined number of TCP request data packets, which may include write register or read register function codes. ModbusTCP2

rvbatista commented 9 months ago

@sunjichao1226 you are communicating with a real device or using a simulator?

At first I was thinking that are one only two requests been packed in one Ethernet frame, but with your last screenshot I started to think that must be related to queuing request while the response of the last request do not arrive.

sunjichao1226 commented 9 months ago

@rvbatista You are right, the first picture is a screenshot of the ModbusTCP server network data frame on the real device, while the second and the third picture is a screenshot of the ModbusTCP network data frame on the simulator. However, when FUXA is configured as a ModbusTCP client to write multiple Float32 type items, its TCP packet will contain multiple ModbusTCP request frames. Different ModbusTCP Servers handle it in different ways. Some will respond to all ModbusTCP requests, and some will only respond the first ModbusTCP request, some will be discarded as abnormal requests. If FUXA ModbusTCP sends a ModbusTCP request that is encapsulated in a TCP packet, you can basically get a correct response. We probably tried increasing the waiting time code in the screenshot. The number of multiple ModbusTCP requests in one TCP will be reduced, but it does not solve the fundamental problem. We are not very good at the programming mechanism of Nodejs. I feel that the problem may be solved by modifying the buffering mechanism of TCP packets or sending TCP packets immediately when each ModbusTCP request is sent. 188cf8eb70e42a018bbbd7bb5a5f8a91 EC54D480-0EAB-4706-B1C7-8474CB2D1C7C

rvbatista commented 9 months ago

@sunjichao1226 I was studying the issue and for me FUXA send the data immediately, but it does using Modbus-serial project, that looks like don't have any kind of buffer.

But Modbus-serial uses node.js net.socket https://nodejs.org/api/net.html#socketwritedata-encoding-callback

And it seems that it's possible because the Modbus-serial code don't use the return or the 'drain' event to separate every Modbus request in different packets.

unocelli commented 9 months ago

I'm not sure I understand the problem, if you mean being able to decide when to send a TCP packet this is not possible in windows because the socket does not handle it deterministically, that's why there are BUS like Profinet

rvbatista commented 9 months ago

@unocelli in Modbus TCP specification is clear that each TCP frame can carry only one Modbus request (MODBUS Messaging on TCP/IP Implementation Guide V1.0b 4.2.1.1 table implementation rules item 6) "A TCP frame must transport only one MODBUS ADU. It is advised against sending multiple MODBUS requests or responses on the same TCP PDU"

And seems to me that FUXA and Modbus-serial don't have any kind of mechanism to avoid combinating Modbus ADUs in one TCP PDU.

unocelli commented 9 months ago

But I don't think that's possible in windows anyway, it's the OS that decides when to send a packet, if the OS is busy doing something else and in the meantime you send two messages to the same address, the OS can combine the 2 messages into one TCP packet to optimise transport