今天收到的一份需求任务是对接硬件,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. python模块之os模块

    os模块 用途:调用封装好的方法调用操作系统的功能,处理文件和目录,OS模块不受平台限制. os.name字符串指示你正在使用的平台.比如对于Windows,它是'nt',而对于Linux/Unix用 ...

  2. python并发编程(并发与并行,同步和异步,阻塞与非阻塞)

    最近在学python的网络编程,学了socket通信,并利用socket实现了一个具有用户验证功能,可以上传下载文件.可以实现命令行功能,创建和删除文件夹,可以实现的断点续传等功能的FTP服务器.但在 ...

  3. RocketMQ_问题_启动报错,修改堆内存大小

    1.启动broker报错 虚拟机内存小,导致虚拟机中的JVM内存小,进而在启动broker时分配JVM内存遇到问题 查询网上得知,查看/usr/local/rocketmq-all-4.3.0/dis ...

  4. jenkins 构建

    自动触发构建 远程构建 本地默认情况下是能够自动构建的,因为浏览器已经登录 了jenkins,如果从别的地方调用的话需要加上用户名和密码做认证,方法如下 curl -u a:a http://Jenk ...

  5. nginx做rails项目web服务器缓存配置方法

    nginx作为Web服务器.或反向代理服务器都可以使用缓存 一.作为Web服务器 nginx可以通过 expires 指令来设置响应头的过期时间,实现浏览器缓存(Browser Caching),即浏 ...

  6. 浏览器内核 Trident Gecko Presto Webkit

    Trident内核:IE,MaxThon,TT,The World,360,搜狗浏览器等 Gecko内核:Netscape6及以上版本,FF,MozillaSuite/SeaMonkey等 Prest ...

  7. GC ROOT

    (GC Root有哪些) 基本思想是通过一系列称为“GC roots”的对象作为起始点,可以作为根节点的是: 虚拟机栈(栈帧中的本地变量表)中引用的对象(即所有Java线程当前活跃的栈帧里指向GC堆里 ...

  8. hbase 实战项目

    首先 根据 hadoop 搭建 + hbase 搭建把 环境弄好 由于 hbase 依赖于 hdfs ,所以 需要 进入 hadoop -->sbin 下 启动 start-dfs.sh , s ...

  9. vmware+centos

    centos 7 在安装的时候使用 net.ifname=0 biosdevname=0 使网卡名和以前一样 /boot 引导系统启动,内核 /swap 交换分区,临时作为内存使用防止内存不够使用导致 ...

  10. vue 获取时间戳对象转换为日期格式

    //1. 简单页面展示用<template> <!-- time为时间戳 --> <div>{{time | formatDate}}</div> &l ...