TCP 通信实现对接硬件发送

收到的一份需求任务是对接硬件,TCP通信,并给出通信端口与数据包格式,如下:

0x01. 首先编写了一个简单的十六进制转 byte[] 数组与 byte[] 转换16进制字符串的两个方法,如下:

 /**
     * 将十六进制的字符串转换成字节数组
     *
     * @param hexString
     * @return
     */
    public static byte[] hexStrToByteArrs(String hexString) {
        if (StringUtils.isEmpty(hexString)) {
            return null;
        }

        hexString = hexString.replaceAll(" ", "");
        int len = hexString.length();
        int index = 0;

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

        while (index < len) {
            String sub = hexString.substring(index, index + 2);
            bytes[index / 2] = (byte) Integer.parseInt(sub, 16);
            index += 2;
        }

        return bytes;
    }


    /**
     * 数组转换成十六进制字符串
     * 
     * @param byte[]
     * @return HexString
     */
    public static final String bytesToHexString(byte[] bArray) {
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

测试

   String string = "C0 10 00 00 00 02 04 00 01 00 00 a2 6f";
   byte[] bs = { -64, 16, 0, 0, 0, 2, 4, 0, 1, 0, 0, -94, 111 };
   System.out.println(Arrays.toString(hexStrToByteArrs(string)));
   System.out.println(bytesToHexString(bs));    

结果

[-64, 16, 0, 0, 0, 2, 4, 0, 1, 0, 0, -94, 111]
C010000000020400010000A26F

补充: 

这里说明一下简单的十六进制转 byte 与 byte 转十六进制的方法

以十六进制的 C0,也就是十进制的 192 为例子

一、十六进制转 byte

// 1.先转为In类型
int parseInt = Integer.parseInt("c0", 16);
// 2.强转为byte
byte b = (byte) parseInt;
System.out.println(parseInt);
System.out.println(b);

结果

192
-64

在这里也明白了实际调用 Integer.parseInt(str) 的时候默认传的是十进制,如下

public static int parseInt(String s) throws NumberFormatException {
   return parseInt(s,10);
}

注意

int 占4个字节,byte 占1个字节,1个字节占8位,那么强制类型转换 int 型截取低8位,对数据也不会造成影响。     

如果再从 byte 型转换成 int型 呢。int 强制转换为 byte 型数据时,会产生一个 -128~127 的有符号字节,所以 byte 转 int 的时候需要根据符号判断。

如下

int intNum = 192;
byte byteNum = (byte) intNum;
int intNum2 = byteNum;
System.out.println(intNum);
System.out.println(byteNum);
System.out.println(intNum2);

结果

192
-64
-64

正确的 byte 转 int 是需要考虑 byte 的符号的,如下:

int intNum = 192;
byte byteNum = (byte) intNum;
int intNum2 = byteNum > 0 ? byteNum : byteNum + 256;
System.out.println(intNum);
System.out.println(byteNum);
System.out.println(intNum2);

结果

192
-64
192

计算机表示正负数 ( 想着明白一下转换原理 )

关于计算机表示正负数的方法:

  • 负数在计算机中的表示为 取反+1,取反+1成为这个数的二进制补码。

  • 最高位为符号位,1负,0正。

以上面的 int 类型192为例子,其二进制表示为:(前面的 xxx 表示24个0,也就是前面3个 byte 都是0)

000...(24个0)    11000000

其转换为 byte 之后是舍掉前3 byte,取低八位,就只剩下11000000。

11000000:  由于第一位是符号位,1代表负数,所以其计算方法是取反加1 (取反之后是: 00111111,加1之后是01000000),转换为十进制就是 -64 。

再以十进制的128为例子:

其 int 型位数如下:    000...(24个0) 10000000

转换为byte之后为 10000000

由于 1 表示为负数,所以先取反为 01111111,再加上 00000001 之后就是10000000,计算结果就是 -128。

int intNum = 128;
byte byteNum = (byte) intNum;
int intNum2 = byteNum > 0 ? byteNum : byteNum + 256;
System.out.println(intNum);
System.out.println(byteNum);
System.out.println(intNum2);

结果:

128
-128
128

二、byte 转16进制的字符串

byte b = -64;
int intNum2 = b > 0 ? b : b + 256;
String string = Integer.toString(intNum2, 16);
System.out.println(string);

结果:

c0

这里需要明白: byte 转为 int 需要根据符号进行转换,原因参考上面的补充;然后调用 Integer.toString(num,radix) 即可实现 int 转换十六进制字符串。

0x02. Java实现TCP协议发送十六进制数据(将十六进制数据转换为byte[])和接收byte数据并转成16进制字符串

服务端: ( 也就是模拟硬件,接受 byte[] 数据并转成16进制 )

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;


public class Server {
    public static void main(String[] args) throws IOException {
        // 1:建立服务器端的tcp socket服务,必须监听一个端口
        ServerSocket ss = new ServerSocket(24992);
        // 2: 通过服务器端的socket对象的accept方法获取连接上的客户端对象
        Socket s = null;
        // 3:获取客户端的数据
        while (true) {
            // 接受Socket服务,如果有,没有则堵塞,等待
            s = ss.accept();
            System.out.println("accept success.......");
            try {
                // 从Socekt输入流中获取客户端发送过来的输出流
                InputStream in = s.getInputStream();
                byte[] buf = new byte[1024];
                int len = in.read(buf);
                System.out.println("从客户端传送来的数据如下:");
                System.out.println(Arrays.toString(buf));


                // 通过服务器端Socket输出流,写数据,会传送到客户端Socket输入流中
                OutputStream out = s.getOutputStream();
                String retunStr = "C0 01 01 03 FF 00 C0";
                out.write(SocketUtils.hexStrToByteArrs(retunStr));
            } catch (Exception e) {
                System.out.println("error");
            } finally {
                s.close();
            }
        }
    }
}

客户端: 模拟发送十六进制数据并且接收十六进制数据

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;


import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import zd.dms.service.config.SystemConfigManager;


public class SocketUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(SocketUtils.class);
    private static Socket socket = null;
    private static String archivesCenterAPIIP = StringUtils
            .defaultString(SystemConfigManager.getInstance().getECMProps("archivesCenterAPIIP"), "127.0.0.1");
    private static String archivesCenterAPIPort = StringUtils
            .defaultString(SystemConfigManager.getInstance().getECMProps("archivesCenterAPIPort"), "24992");


    public static boolean connection() {
        if (socket != null) {
            return true;
        }


        try {
            socket = new Socket(archivesCenterAPIIP, NumberUtils.toInt(archivesCenterAPIPort));
            return true;
        } catch (Exception e) {
            LOGGER.error("connection error", e);
            return false;
        }
    }


    public static void stop() {
        try {
            if (socket != null) {
                socket.close();
                socket = null;
            }
        } catch (Exception e) {
            LOGGER.error("connection error", e);
        }
    }


    /**
     * 发送数据
     * 
     * @param cmd
     *            需要发送的数据(十六进制的字符串形式)
     * @return 接受到的数据(十六进制的字符串形式)
     */
    public static String sendCmd(String cmd) {
        if (!connection() || socket == null) {
            return "error";
        }


        try {
            OutputStream out = socket.getOutputStream();
            byte[] hexStrToByteArrs = hexStrToByteArrs(cmd);
            if (hexStrToByteArrs == null) {
                return "error";
            }
            out.write(hexStrToByteArrs);


            InputStream in = socket.getInputStream();
            byte[] buf = new byte[1024];
            int len = in.read(buf);


            stop();


            return bytesToHexString(buf);
        } catch (IOException e) {
            LOGGER.error("sendCmd error", e);
            return "error";
        }
    }


    /**
     * 将十六进制的字符串转换成字节数组
     *
     * @param hexString
     * @return
     */
    public static byte[] hexStrToByteArrs(String hexString) {
        if (StringUtils.isEmpty(hexString)) {
            return null;
        }


        hexString = hexString.replaceAll(" ", "");
        int len = hexString.length();
        int index = 0;


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


        while (index < len) {
            String sub = hexString.substring(index, index + 2);
            bytes[index / 2] = (byte) Integer.parseInt(sub, 16);
            index += 2;
        }


        return bytes;
    }


    /**
     * 数组转换成十六进制字符串
     * 
     * @param byte[]
     * @return HexString
     */
    public static final String bytesToHexString(byte[] bArray) {
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
            // 在这里故意追加一个逗号便于最后的区分
            sb.append(" ");
        }
        return sb.toString();
    }


    public static void main(String[] args) {
        System.out.println(sendCmd("0f 0f"));
        System.out.println(sendCmd("0f 0f"));
    }
}

先启动服务端,然后启动服务端之后查看控制台:

服务器控制台

客户端控制台

0x03. 总结

目前来看是可行的,但是还没有去对接硬件,在对接完成之后再继续补充此方法是否可以成功的实现对接硬件并向硬件发送命令。  

验证完之后也是可行的。

补充: 十进制数字转换二进制、八进制和16进制字符串的方法:

System.out.println(Integer.toBinaryString(25));// 转换为二进制字符串
System.out.println(Integer.toOctalString(25));// 转换为8进制字符串
System.out.println(Integer.toHexString(25));// 转换为16进制字符串

结果

11001
31
19

补充: 字符串按照进制转换为十进制数的方法:

System.out.println(Integer.parseInt("11001", 2));// 二进制字符串转换十进制数
System.out.println(Integer.parseInt("31", 8));// 8进制字符串转换十进制数
System.out.println(Integer.parseInt("19", 16));// 16进制字符串转换十进制数

结果

25
25
25
source: https://www.cnblogs.com/qlqwjy/p/10477652.html

喜欢,在看

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值