今天收到的一份需求任务是对接硬件,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 < 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为例子。

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

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

服务器控制台:

客户端控制台:

总结:

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

  验证完之后也是可行的。

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

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

  1. msgrcv,msgsnd进程通信,消息的发送和接收

    //进程通信,消息的发送和接收 //client.c #include <unistd.h> #include <sys/types.h> #include <sys/s ...

  2. PHP发送和接收POST数据

    1. 发送post数据 $data = '{ "id": "17999030", "method": "sayHello" ...

  3. Delphi---TServerSocket和TClientSocket发送和接收大数据包

    https://www.cnblogs.com/zhangzhifeng/p/6065244.html TServerSocket和TClientSocket用非阻塞模式发送和接收比较大的数据时,可能 ...

  4. (四)XML基础(客户端和服务端发送与接收xml数据)

    案例: index.jsp <%@ page language="java" import="java.util.*" pageEncoding=&quo ...

  5. Jquery的$.ajax、$.get、$.post发送、接收JSON数据及回调函数用法

    平时研究代码时,经常会遇到AJAX的相关用法,做项目时才真正体会到Ajax的强大之处(与服务器数据交互如此之便捷,更新DOM节点而不用刷新整个页面),以及运用的频繁程度.今天整理了一下自己之前没搞清楚 ...

  6. Java 网络编程 字符流的发送与接收 自定义数据边界

    在网络编程中,客户端调用了flush方法,就会将缓存在字符流中的文本发送给服务器,服务器该怎样判断客户端发送的文本已经结束了呢? 我们先看一个例子: 客户端: import java.io.IOExc ...

  7. Java实现RS485串口通信,发送和接收数据进行解析

    最近项目有一个空气检测仪,需要得到空气检测仪的实时数据,保存到数据库当中.根据了解得到,硬件是通过rs485进行串口通讯的,需要发送16进制命令给仪器,然后通过轮询来得到数据. 需要先要下载RXTX的 ...

  8. JAVASE02-Unit011: TCP通信(小程序)

    TCP通信(小程序) server端: package chat; import java.io.BufferedReader; import java.io.IOException; import ...

  9. 等待唤醒机制,UDP通信和TCP通信

    等待唤醒机制 通过等待唤醒机制使各个线程能有效的利用资源. 等待唤醒机制所涉及到的方法: wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中. notify():唤醒, ...

随机推荐

  1. java的零拷贝机制

    转:https://blog.csdn.net/zhouhao88410234/article/details/77574689?fps=1&locationNum=9 为何要懂零拷贝原理?因 ...

  2. 过滤富文本编辑器中的html元素和其他元素

    https://blog.csdn.net/fjssharpsword/article/details/53467079 1.应用场景:从一份html文件中或从String(是html内容)中提取纯文 ...

  3. Python三十个常见的脚本汇总

    1.冒泡排序     2.计算x的n次方的方法     这里有我自己整理了一套最新的python系统学习教程,包括从基础的python脚本到web开发.爬虫.数据分析.数据可视化.机器学习等.送给正在 ...

  4. league之csv导出

    有的时候当我们导出文件时,如果文件比较小可以使用phpexcel,但是当文件太大时就会遇到很多瓶颈(excel条数限制.导出时间太长等). 这个时候要么使用excel分批次导出,要么就需要使用csv导 ...

  5. 使用WinPcap(SharpPcap)实现ARP抓包以实现设备IP修改功能

    参考上一篇: 使用WinPcap(SharpPcap)实现ARP抓包以实现设备IP搜索功能 搜索出设备后,需要修改设备IP网关掩码等信息 继续采用ARP包 getBas类似之前的,根据用户电脑的网卡物 ...

  6. 启动oracle的步骤

    启动oracle的步骤 Linux下启动oracle分为以下两步: 1.1.启动lsnrctl监听. 1.2.启动数据库实例. 启动oracle监听 首先登陆服务器,切换到oracle用户. [adm ...

  7. "Error 0162 - Setup data integrity check failure" after updating BIOS via Thinkvantage

    Start the computer and start pressing F1 and get into set up. In setup press F9 for default settings ...

  8. Docker 容器管理

    单一容器管理 容器的标识符 每个容器被创建后都会分配一个CONTAINER_ID作为容器的唯一标识符,后续的启动.停止等操作都通过CONTAINER_ID来完成的. CONTAINER_ID很难记忆, ...

  9. Hbase记录-zookeeper部署

    #官网下载二进制包解压到/usr/app下,配置/etc/profile: export ZOOKEEPER_HOME=/usr/app/zookeeper export PATH=$PATH:$ZO ...

  10. Java笔记——泛型擦除

    1. 泛型擦除 package cn.Douzi.T_Demo; import java.util.ArrayList; /** * @Auther: Douzi * @Date: 2019/3/8 ...