好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

java利用socket通信实现Modbus-RTU通信协议的示例代码

Modbus

Modbus是一种串行通信协议。Modbus 一个工业上常用的通讯协议、一种通讯约定。Modbus协议包括RTU、ASCII、TCP。其中MODBUS-RTU最常用,比较简单,在单片机上很容易实现。

简单分析Modbus-RTU报文

37 03 10 3F 80 00 00 00 00 00 00 3F 80 00 00 40 40 00 00 24 dd(十六进制)
37:从站地址 ,03:功能码,10:读取的字节数,24 dd:crc校验码。其它就是传送的数据。

4G DTU(ZHC4013)

ZHC4012是一款全网通七模4G DTU,支持2G/3G/4G信号透明传输。支持工业RS232/485等接口,直接连接设备传输。这个硬件是我项目中实践过的,该设备可以通过4G运营商网络与远程服务器进行数据通信。具体操作可以到官网联系客服。 设备官网4G DTU(ZHC4013)

项目支持多个4G DTU设备数据上传,支持控制指定4G DTU设备。

附一个测试版本的源代码

用到的工具类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

package hdo.utils;

 

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;

 

public class ModBusUtils {

 

     public static byte [] readInputStream(InputStream inputStream) throws IOException {

         byte [] buffer = new byte [ 1024 ];

         int len = 0 ;

         ByteArrayOutputStream bos = new ByteArrayOutputStream();

         if ((len = inputStream.read(buffer)) != - 1 ) {

             bos.write(buffer, 0 , len);

         }

         bos.close();

         return bos.toByteArray();

     }

    

     public static char byteToASCLL( byte b){

         return ( char ) b;

     }

   

     /*

      * 字节数组转16进制字符串

      */

     public static String bytes2HexString(byte[] b) {

         String r = "";

         for (int i = 0; i < b.length; i++) {

             String hex = Integer.toHexString(b[i] & 0xFF);

             if (hex.length() == 1) {

                 hex = '0' + hex;

             }

             r += hex.toUpperCase()+" ";

         }

         return r;

     }

 

  /**

   * @TODO : 计算CRC校验码

   * @AUTH : linfeng

   * @DATE : 2020年8月27日 下午2:11:30

   * @return_type : String

   * @param data

   * @return

   */

  public static String getCRC3(byte[] data) {

         byte[] crc16_h = {

                 (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,

                 (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,

                 (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,

                 (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,

                 (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,

                 (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,

                 (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,

                 (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,

                 (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,

                 (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,

                 (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,

                 (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,

                 (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,

                 (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,

                 (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,

                 (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40

         };

 

         byte[] crc16_l = {

                 (byte) 0x00, (byte) 0xC0, (byte) 0xC1, (byte) 0x01, (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2, (byte) 0xC6, (byte) 0x06, (byte) 0x07, (byte) 0xC7, (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04,

                 (byte) 0xCC, (byte) 0x0C, (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE, (byte) 0x0E, (byte) 0x0A, (byte) 0xCA, (byte) 0xCB, (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8,

                 (byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB, (byte) 0xDA, (byte) 0x1A, (byte) 0x1E, (byte) 0xDE, (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D, (byte) 0x1C, (byte) 0xDC,

                 (byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7, (byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2, (byte) 0x12, (byte) 0x13, (byte) 0xD3, (byte) 0x11, (byte) 0xD1, (byte) 0xD0, (byte) 0x10,

                 (byte) 0xF0, (byte) 0x30, (byte) 0x31, (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32, (byte) 0x36, (byte) 0xF6, (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35, (byte) 0x34, (byte) 0xF4,

                 (byte) 0x3C, (byte) 0xFC, (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE, (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39, (byte) 0xF9, (byte) 0xF8, (byte) 0x38,

                 (byte) 0x28, (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B, (byte) 0x2A, (byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF, (byte) 0x2D, (byte) 0xED, (byte) 0xEC, (byte) 0x2C,

                 (byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5, (byte) 0x27, (byte) 0xE7, (byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2, (byte) 0xE3, (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0,

                 (byte) 0xA0, (byte) 0x60, (byte) 0x61, (byte) 0xA1, (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66, (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64, (byte) 0xA4,

                 (byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E, (byte) 0xAE, (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9, (byte) 0xA8, (byte) 0x68,

                 (byte) 0x78, (byte) 0xB8, (byte) 0xB9, (byte) 0x79, (byte) 0xBB, (byte) 0x7B, (byte) 0x7A, (byte) 0xBA, (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF, (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C,

                 (byte) 0xB4, (byte) 0x74, (byte) 0x75, (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6, (byte) 0x76, (byte) 0x72, (byte) 0xB2, (byte) 0xB3, (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0,

                 (byte) 0x50, (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53, (byte) 0x52, (byte) 0x92, (byte) 0x96, (byte) 0x56, (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94, (byte) 0x54,

                 (byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F, (byte) 0x9F, (byte) 0x9E, (byte) 0x5E, (byte) 0x5A, (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99, (byte) 0x59, (byte) 0x58, (byte) 0x98,

                 (byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89, (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A, (byte) 0x4E, (byte) 0x8E, (byte) 0x8F, (byte) 0x4F, (byte) 0x8D, (byte) 0x4D, (byte) 0x4C, (byte) 0x8C,

                 (byte) 0x44, (byte) 0x84, (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86, (byte) 0x82, (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40

         };

 

         int crc = 0x0000ffff;

         int ucCRCHi = 0x00ff;

         int ucCRCLo = 0x00ff;

         int iIndex;

         for (int i = 0; i < data.length; ++i) {

             iIndex = (ucCRCLo ^ data[i]) & 0x00ff;

             ucCRCLo = ucCRCHi ^ crc16_h[iIndex];

             ucCRCHi = crc16_l[iIndex];

         }

 

         crc = ((ucCRCHi & 0x00ff) << 8) | (ucCRCLo & 0x00ff) & 0xffff;

         //高低位互换,输出符合相关工具对Modbus CRC16的运算

         crc = ((crc & 0xFF00) >> 8) | ((crc & 0x00FF) << 8);

         return String.format("%04X", crc);

     }

 

   /**

      * 16进制表示的字符串转换为字节数组

      *

      * @param hexString 16进制表示的字符串

      * @return byte[] 字节数组

      */

     public static byte [] hexStringToByteArray(String hexString) {

         hexString = hexString.replaceAll( " " , "" );

         int len = hexString.length();

         byte [] bytes = new byte [len / 2 ];

         for ( int i = 0 ; i < len; i += 2 ) {

             // 两位一组,表示一个字节,把这样表示的16进制字符串,还原成一个字节

             bytes[i / 2 ] = ( byte ) ((Character.digit(hexString.charAt(i), 16 ) << 4 ) + Character

                     .digit(hexString.charAt(i + 1 ), 16 ));

         }

         return bytes;

     }

 

}

服务端代码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

package hdo.utils.thread;

 

import java.io.InputStream;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.HashMap;

import java.util.Map;

 

import hdo.utils.ModBusUtils;

 

public class SocketServer extends Thread {

 

  public Map<String,Socket> clientMap = new HashMap<>();

 

  public void run() {

         try {

             //创建socket服务端

             @SuppressWarnings ( "resource" )

    ServerSocket server = new ServerSocket( 9666 );

             while ( true ){

                 System.out.println( "建立监听" );

                 Socket client = server.accept();

                 System.out.println( "建立连接" );

                 //获取注册包

                 InputStream is = client.getInputStream();

                 byte [] bytes = ModBusUtils.readInputStream(is);

                 String str = "" ;

                 for ( int i= 0 ;i<bytes.length;i++) {

                     if (i== 0 ){

                         System.out.print( "十进制:" +bytes[i]+ " " );

                     } else {

                         System.out.print(bytes[i]+ " " );

                     }

                     str=str+ModBusUtils.byteToASCLL(bytes[i]);

                 }

                 System.out.println( "十六进制:" +ModBusUtils.bytes2HexString(bytes));

                 System.out.println( "注册包:" +str);

                 //添加客户端

                 clientMap.put(str,client);

                 Service service = new Service(clientMap);

                 service.start();

             }

   } catch (Exception e) {

    e.printStackTrace();

   }

  }

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

package com.ruoyi.test;

 

import java.io.InputStream;

import java.io.OutputStream;

import java.net.Socket;

import java.util.*;

 

/**

  * TODO

  *

  * @author linfeng

  * @date 2021/4/13 17:50

  */

public class Service extends Thread {

     private Map<String, Socket> clientMap = new HashMap<>();

 

     public Service(){

     }

 

     public Service(Map<String,Socket> clientMap){

         this .clientMap=clientMap;

     }

 

     public void run() {

         while ( true ) {

             try {

                 for (Map.Entry<String, Socket> entry : clientMap.entrySet()) {

                     //注册包 节点编号

                     String registrationPacket = entry.getKey();

                     Socket socket = entry.getValue();

                     assert socket != null ;

                     InputStream is = socket.getInputStream();

                     OutputStream os = socket.getOutputStream();

                     if (is.available() != 0 ) {

                         byte [] bytes = ModBusUtils.readInputStream(is);

                         String str = ModBusUtils.bytes2HexString(bytes);

                         System.out.print( "十六进制:" + str);

                         //截取对应的数据

                         List<Float> floatList = new ArrayList<>();

                         String[] arr = str.split( " " );

                         if (arr.length > 20 ) {

                             for ( int i = 7 ; i < arr.length - 2 ; i += 4 ) {

                                 String a = arr[i] + arr[i + 1 ] + arr[i + 2 ] + arr[i + 3 ];

                                 Float f = Float.intBitsToFloat(Integer.valueOf(a, 16 ));

                                 System.out.print( "浮点数:" + f);

                                 floatList.add(f);

                             }

                         }

                         System.out.println( "节点编号:" + registrationPacket);

                         byte [] by = new byte [ 19 ];

                         by[ 0 ] = 55 ;

                         by[ 1 ] = 3 ;

                         by[ 2 ] = 16 ;

                         by[ 3 ] = 63 ;

                         by[ 4 ] = - 128 ;

                         by[ 5 ] = 0 ;

                         by[ 6 ] = 0 ;

                         by[ 7 ] = 0 ;

                         by[ 8 ] = 0 ;

                         by[ 9 ] = 0 ;

                         by[ 10 ] = 0 ;

                         by[ 11 ] = 0 ;

                         by[ 12 ] = 0 ;

                         by[ 13 ] = 0 ;

                         by[ 14 ] = 0 ;

                         String hexStr = Integer.toHexString(Float.floatToIntBits(Float.parseFloat( "2.0" )));

                         byte [] b = ModBusUtils.hexStringToByteArray(hexStr);

                         by[ 15 ] = b[ 0 ];

                         by[ 16 ] = b[ 1 ];

                         by[ 17 ] = b[ 2 ];

                         by[ 18 ] = b[ 3 ];

                         //crc3校验

                         String crc = ModBusUtils.getCRC3(by);

                         byte [] crcByte = ModBusUtils.hexStringToByteArray(crc);

                         byte [] data = new byte [ 21 ];

                         data[ 19 ] = crcByte[ 0 ];

                         data[ 20 ] = crcByte[ 1 ];

                         for ( int i = 0 ; i < by.length; i++) {

                             data[i] = by[i];

                         }

                         os.write(data);

                         System.out.println(registrationPacket + ":写入数据:" + Arrays.toString(data));

                     } else {

                         continue ;

                     }

                 }

             } catch (Exception e) {

                 e.printStackTrace();

             }

             try {

                 Thread.sleep( 5000 );

             } catch (InterruptedException e) {

                 e.printStackTrace();

             }

         }

     }

}

到此这篇关于java利用socket通信实现Modbus-RTU通信协议的示例代码的文章就介绍到这了,更多相关java Modbus-RTU通信协议内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

原文链接:https://blog.csdn.net/qq_40042416/article/details/115672989

查看更多关于java利用socket通信实现Modbus-RTU通信协议的示例代码的详细内容...

  阅读:93次