rossmann-engineering/EasyModbusTCP.NET

Modbus TCP server can not handle a client connection where the data length is greater than 125

ListGrid opened this issue · 3 comments

When the client's data length is greater than 200, Modbus TCP server seems do nothing.
When the client's data length is greater than 125 and less than 200, Modbus TCP server corrupt.
As I konw there are other modbus TCP servers that can work correctly when the client's data length is greater than 255.

I use the following code, then Modbus TCP server will not corrup when the client's data length is greater than 125 and less than 200. But now I find that the client's data length is not allowed to be greater than 125 in the modbus tcp/ip protocol.
private void ReadHoldingRegisters(ModbusProtocol receiveData, ModbusProtocol sendData, NetworkStream stream, int portIn, IPAddress ipAddressIn)
{
UInt16 dataLength = 0;
sendData.response = true;

        sendData.transactionIdentifier = receiveData.transactionIdentifier;
        sendData.protocolIdentifier = receiveData.protocolIdentifier;

        sendData.unitIdentifier = this.unitIdentifier;
        sendData.functionCode = receiveData.functionCode;
        if ((receiveData.quantity < 1) | (receiveData.quantity > 0x017D))  //Invalid quantity
        {
            sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
            sendData.exceptionCode = 3;
        }
        if (((receiveData.startingAdress + 1 + receiveData.quantity) > 65535)  | (receiveData.startingAdress < 0))   //Invalid Starting adress or Starting address + quantity
        {
            sendData.errorCode = (byte)(receiveData.functionCode + 0x80);
            sendData.exceptionCode = 2;
        }
        if (sendData.exceptionCode == 0)
        {
            dataLength = (UInt16)(2 * receiveData.quantity);
            sendData.sendRegisterValues = new Int16[receiveData.quantity];
            lock (lockHoldingRegisters)
                Buffer.BlockCopy(holdingRegisters.localArray, receiveData.startingAdress * 2 + 2, sendData.sendRegisterValues, 0, receiveData.quantity * 2);
        }
            if (sendData.exceptionCode > 0)
                sendData.length = 0x03;
            else
                sendData.length = (ushort)(0x03 + dataLength);
        
        if (true)
        {
            Byte[] data;
            if (sendData.exceptionCode > 0)
                data = new byte[9 + 2 * Convert.ToInt32(serialFlag)];
            else
                data = new byte[9 + dataLength + 2 * Convert.ToInt32(serialFlag)];
            Byte[] byteData = new byte[2];
            sendData.length = (UInt16)(data.Length - 6);

            //Send Transaction identifier
            byteData = BitConverter.GetBytes((int)sendData.transactionIdentifier);
            data[0] = byteData[1];
            data[1] = byteData[0];

            //Send Protocol identifier
            byteData = BitConverter.GetBytes((int)sendData.protocolIdentifier);
            data[2] = byteData[1];
            data[3] = byteData[0];

            //Send length
            byteData = BitConverter.GetBytes((int)sendData.length);
            data[4] = byteData[1];
            data[5] = byteData[0];

            //Unit Identifier
            data[6] = sendData.unitIdentifier;

            //Function Code
            data[7] = sendData.functionCode;

            //ByteCount
            data[8] = sendData.byteCount;

            if (sendData.exceptionCode > 0)
            {
                data[7] = sendData.errorCode;
                data[8] = sendData.exceptionCode;
                sendData.sendRegisterValues = null;
            }


            if (sendData.sendRegisterValues != null)
                for (int i = 0; i < (dataLength / 2); i++)
                {
                    byteData = BitConverter.GetBytes((Int16)sendData.sendRegisterValues[i]);
                    data[9 + i * 2] = byteData[1];
                    data[10 + i * 2] = byteData[0];
                }
            try
            {
                if (serialFlag)
                {
                    if (!serialport.IsOpen)
                        throw new EasyModbus.Exceptions.SerialPortNotOpenedException("serial port not opened");
                    //Create CRC
                    sendData.crc = ModbusClient.calculateCRC(data, Convert.ToUInt16(data.Length - 8), 6);
                    byteData = BitConverter.GetBytes((int)sendData.crc);
                    data[data.Length - 2] = byteData[0];
                    data[data.Length - 1] = byteData[1];
                    serialport.Write(data, 6, data.Length - 6);
                    if (debug)
                    {
                        byte[] debugData = new byte[data.Length - 6];
                        Array.Copy(data, 6, debugData, 0, data.Length - 6);
                        if (debug) StoreLogData.Instance.Store("Send Serial-Data: " + BitConverter.ToString(debugData), System.DateTime.Now);
                    }
                }
                else if (udpFlag)
                {
                    //UdpClient udpClient = new UdpClient();
                    IPEndPoint endPoint = new IPEndPoint(ipAddressIn, portIn);
                    udpClient.Send(data, data.Length, endPoint);

                }
                else
                {
                    stream.Write(data, 0, data.Length);
                    if (debug) StoreLogData.Instance.Store("Send Data: " + BitConverter.ToString(data), System.DateTime.Now);
                }
            }
            catch (Exception) { }
        }       
    }

In modbus TCP, the PDU can't be longer than 253 bytes. Therefore if the line

if ((receiveData.quantity < 1) | (receiveData.quantity > 0x007D)) //Invalid quantity

refers to PDU length, it then needs to be changed to 0x00FD

Thanks a lot. I am not familiar with the Modbus Protocol. Yes, in modbus TCP, the PDU can't be longer than 253 bytes.
The client's data length is not allowed to be greater than 200, which is a restricion applied by my modbus client software. So the request from my modbus client software is not sent to the server.