热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

TCP通信实现对接硬件发送与接收十六进制数据&int与byte的转换原理&java中正负数的表示

今天收到的一份需求任务是对接硬件,TCP通信,并给出通信端口与数据包格式,如下:1.首先编写了一个简单的十六进制转byte[]数组与byte[]转换16进制字符串的两个方法,如下:

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

 

1.首先编写了一个简单的十六进制转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 ) {
            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为例子。

(1)十六进制转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成为这个数的二进制补码。

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

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

000...(24个0)    11000000

其转换为byte之后是舍掉前3byte,取低八位,就只剩下 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

 

(2)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转换十六进制字符串。

 

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

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

package zd.dms.socket;

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();
            }
        }
    }
}

 

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

package zd.dms.socket;

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 ) {
            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"));
    }
}

 

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

服务器控制台:

 

客户端控制台:

 

总结:

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

  验证完之后也是可行的。

 

补充:十进制数字转换二进制、八进制和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

 


推荐阅读
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • ***byte(字节)根据长度转成kb(千字节)和mb(兆字节)**parambytes*return*publicstaticStringbytes2kb(longbytes){ ... [详细]
  • 本文整理了Java中java.lang.NoSuchMethodError.getMessage()方法的一些代码示例,展示了NoSuchMethodErr ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文介绍了Android中的assets目录和raw目录的共同点和区别,包括获取资源的方法、目录结构的限制以及列出资源的能力。同时,还解释了raw目录中资源文件生成的ID,并说明了这些目录的使用方法。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • 微信官方授权及获取OpenId的方法,服务器通过SpringBoot实现
    主要步骤:前端获取到code(wx.login),传入服务器服务器通过参数AppID和AppSecret访问官方接口,获取到OpenId ... [详细]
  • 本文介绍了解决java开源项目apache commons email简单使用报错的方法,包括使用正确的JAR包和正确的代码配置,以及相关参数的设置。详细介绍了如何使用apache commons email发送邮件。 ... [详细]
  • 使用freemaker生成Java代码的步骤及示例代码
    本文介绍了使用freemaker这个jar包生成Java代码的步骤,通过提前编辑好的模板,可以避免写重复代码。首先需要在springboot的pom.xml文件中加入freemaker的依赖包。然后编写模板,定义要生成的Java类的属性和方法。最后编写生成代码的类,通过加载模板文件和数据模型,生成Java代码文件。本文提供了示例代码,并展示了文件目录结构。 ... [详细]
author-avatar
永远的菜鸟
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有