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.