java利用socket通信實(shí)現(xiàn)Modbus-RTU通信協(xié)議的示例代碼
Modbus
Modbus是一種串行通信協(xié)議。Modbus 一個(gè)工業(yè)上常用的通訊協(xié)議、一種通訊約定。Modbus協(xié)議包括RTU、ASCII、TCP。其中MODBUS-RTU最常用,比較簡(jiǎn)單,在單片機(jī)上很容易實(shí)現(xiàn)。
簡(jiǎn)單分析Modbus-RTU報(bào)文
37 03 10 3F 80 00 00 00 00 00 00 3F 80 00 00 40 40 00 00 24 dd(十六進(jìn)制)
37:從站地址 ,03:功能碼,10:讀取的字節(jié)數(shù),24 dd:crc校驗(yàn)碼。其它就是傳送的數(shù)據(jù)。
4G DTU(ZHC4013)
ZHC4012是一款全網(wǎng)通七模4G DTU,支持2G/3G/4G信號(hào)透明傳輸。支持工業(yè)RS232/485等接口,直接連接設(shè)備傳輸。這個(gè)硬件是我項(xiàng)目中實(shí)踐過(guò)的,該設(shè)備可以通過(guò)4G運(yùn)營(yíng)商網(wǎng)絡(luò)與遠(yuǎn)程服務(wù)器進(jìn)行數(shù)據(jù)通信。具體操作可以到官網(wǎng)聯(lián)系客服。設(shè)備官網(wǎng)4G DTU(ZHC4013)
項(xiàng)目支持多個(gè)4G DTU設(shè)備數(shù)據(jù)上傳,支持控制指定4G DTU設(shè)備。
附一個(gè)測(cè)試版本的源代碼
用到的工具類(lèi)
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; } /* * 字節(jié)數(shù)組轉(zhuǎn)16進(jìn)制字符串 */ 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 : 計(jì)算CRC校驗(yàn)碼 * @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; //高低位互換,輸出符合相關(guān)工具對(duì)Modbus CRC16的運(yùn)算 crc = ((crc & 0xFF00) >> 8) | ((crc & 0x00FF) << 8); return String.format("%04X", crc); } /** * 16進(jìn)制表示的字符串轉(zhuǎn)換為字節(jié)數(shù)組 * * @param hexString 16進(jìn)制表示的字符串 * @return byte[] 字節(jié)數(shù)組 */ 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) { // 兩位一組,表示一個(gè)字節(jié),把這樣表示的16進(jìn)制字符串,還原成一個(gè)字節(jié) bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character .digit(hexString.charAt(i + 1), 16)); } return bytes; } }
服務(wù)端代碼
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 { //創(chuàng)建socket服務(wù)端 @SuppressWarnings("resource") ServerSocket server = new ServerSocket(9666); while (true){ System.out.println("建立監(jiān)聽(tīng)"); Socket client = server.accept(); System.out.println("建立連接"); //獲取注冊(cè)包 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("十進(jìn)制:"+bytes[i]+" "); }else { System.out.print(bytes[i]+" "); } str=str+ModBusUtils.byteToASCLL(bytes[i]); } System.out.println("十六進(jìn)制:"+ModBusUtils.bytes2HexString(bytes)); System.out.println("注冊(cè)包:"+str); //添加客戶(hù)端 clientMap.put(str,client); Service service = new Service(clientMap); service.start(); } } catch (Exception e) { e.printStackTrace(); } } }
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()) { //注冊(cè)包 節(jié)點(diǎn)編號(hào) 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("十六進(jìn)制:" + str); //截取對(duì)應(yīng)的數(shù)據(jù) 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("浮點(diǎn)數(shù):" + f); floatList.add(f); } } System.out.println("節(jié)點(diǎn)編號(hào):" + 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校驗(yàn) 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 + ":寫(xiě)入數(shù)據(jù):" + Arrays.toString(data)); } else { continue; } } } catch (Exception e) { e.printStackTrace(); } try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
到此這篇關(guān)于java利用socket通信實(shí)現(xiàn)Modbus-RTU通信協(xié)議的示例代碼的文章就介紹到這了,更多相關(guān)java Modbus-RTU通信協(xié)議內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于Springboot使用logback的注意事項(xiàng)
這篇文章主要介紹了Springboot使用logback的注意事項(xiàng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07SpringBoot 回滾操作的幾種實(shí)現(xiàn)方式
回滾操作是一種常見(jiàn)的操作,用于撤銷(xiāo)之前執(zhí)行的操作,本文主要介紹了SpringBoot回滾操作的幾種實(shí)現(xiàn)方式,包含基于異常類(lèi)型的回滾、基于自定義邏輯的回滾和基于數(shù)據(jù)庫(kù)狀態(tài)的回滾,感興趣的可以了解一下2024-03-03使用Feign消費(fèi)服務(wù)時(shí)POST/GET請(qǐng)求方式詳解
這篇文章主要介紹了使用Feign消費(fèi)服務(wù)時(shí)POST/GET請(qǐng)求方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06SpringBoot 改造成https訪(fǎng)問(wèn)的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot 改造成https訪(fǎng)問(wèn)的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10詳解Java的堆內(nèi)存與棧內(nèi)存的存儲(chǔ)機(jī)制
這篇文章主要介紹了Java的堆內(nèi)存與棧內(nèi)存的存儲(chǔ)機(jī)制,包括JVM的內(nèi)存優(yōu)化和GC等相關(guān)方面內(nèi)容,需要的朋友可以參考下2016-01-01淺談SpringMVC請(qǐng)求映射handler源碼解讀
這篇文章主要介紹了淺談SpringMVC請(qǐng)求映射handler源碼解讀,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03通過(guò)Mybatis實(shí)現(xiàn)單表內(nèi)一對(duì)多的數(shù)據(jù)展示示例代碼
最近做項(xiàng)目遇到這樣的需求要求將表中的數(shù)據(jù),按照一級(jí)二級(jí)分類(lèi)返回給前端json數(shù)據(jù),下面通過(guò)本文給大家分享通過(guò)Mybatis實(shí)現(xiàn)單表內(nèi)一對(duì)多的數(shù)據(jù)展示示例代碼,感興趣的朋友參考下吧2017-08-08Spring定時(shí)任務(wù)@scheduled多線(xiàn)程使用@Async注解示例
這篇文章主要為大家介紹了Spring定時(shí)任務(wù)@scheduled多線(xiàn)程使用@Async注解示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11