今天收到的一份需求任务是对接硬件,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. CRT和EXCRT学习笔记

    蒟蒻maomao终于学会\(CRT\)啦!发一篇博客纪念一下(还有防止忘掉) \(CRT\)要解决的是这样一个问题: \[x≡a_1​(mod m_1​)\] \[x≡a_2​(mod m_2​)\] ...

  2. 【 强大的Mac/iOS开发工具】AppCode for Mac 2017.3

    [简介] 最新的 AppCode 2017.3 版本,完全支持最新的Swift 4.0语言,这是一款JetBrain出品的强大的OS X 和 iOS开发工具,AppCode可以用于开发 Mac OS ...

  3. ansible playbook 变量

    变量优先级 在命令中定义的变量(-e参数指定的) 在inventory中定义的变量(ansible_ssh_user等) 其他变量(role中.play中) 系统通过father_facts定义的变量 ...

  4. I/O模型之四:Java 浅析I/O模型(BIO、NIO、AIO、Reactor、Proactor)

    目录: <I/O模型之一:Unix的五种I/O模型> <I/O模型之二:Linux IO模式及 select.poll.epoll详解> <I/O模型之三:两种高性能 I ...

  5. Linux环境变量总结

    现在每天测试到时候会与Linux打交道,自然也会用到环境变量了.看了网上几篇文章,结合自己到实践和看法,总结以下Linux的环境变量吧.一.什么是环境变量?环境变量相当于给系统或用户应用程序设置的一些 ...

  6. js中得计算问题算式结果拼接成字符串怎么解决

    如题:经常遇到类似问题 一种:自定义的弱类型 var savNum=0; var num=$("#numU").val();//jsp页面获得得值 savNum=parseInt( ...

  7. Golang入门教程(三)beego 框架安装

    beego 是一个快速开发 Go 应用的 HTTP 框架,他可以用来快速开发 API.Web 及后端服务等各种应用,是一个 RESTful 的框架,主要设计灵感来源于 tornado.sinatra ...

  8. .net程序集

    单程序集 多个.dll或exe 文件 多程序集 单个.dll或exe 文件 单程序集 是一个单一 独立明确定义的包,这个包中包含有程序集清单,CIL和类型元数据 多程序集程序集基本由二进制文件组成(称 ...

  9. ext.net gridlist选择内部元素时自动选择所在行

    function changeSelection(id) { var index = 0; for (var i = 0; i < mcp_liststore.data.length; i++) ...

  10. 1.redis安装

    一.安装 1.安装 tar fvxz redis-3.0.7.tar.gz  ln -s redis-3.0.7 redis cd redis make && make install ...