TCP通信实现对接硬件发送与接收十六进制数据 & int与byte的转换原理 & java中正负数的表示
今天收到的一份需求任务是对接硬件,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中正负数的表示的更多相关文章
- msgrcv,msgsnd进程通信,消息的发送和接收
//进程通信,消息的发送和接收 //client.c #include <unistd.h> #include <sys/types.h> #include <sys/s ...
- PHP发送和接收POST数据
1. 发送post数据 $data = '{ "id": "17999030", "method": "sayHello" ...
- Delphi---TServerSocket和TClientSocket发送和接收大数据包
https://www.cnblogs.com/zhangzhifeng/p/6065244.html TServerSocket和TClientSocket用非阻塞模式发送和接收比较大的数据时,可能 ...
- (四)XML基础(客户端和服务端发送与接收xml数据)
案例: index.jsp <%@ page language="java" import="java.util.*" pageEncoding=&quo ...
- Jquery的$.ajax、$.get、$.post发送、接收JSON数据及回调函数用法
平时研究代码时,经常会遇到AJAX的相关用法,做项目时才真正体会到Ajax的强大之处(与服务器数据交互如此之便捷,更新DOM节点而不用刷新整个页面),以及运用的频繁程度.今天整理了一下自己之前没搞清楚 ...
- Java 网络编程 字符流的发送与接收 自定义数据边界
在网络编程中,客户端调用了flush方法,就会将缓存在字符流中的文本发送给服务器,服务器该怎样判断客户端发送的文本已经结束了呢? 我们先看一个例子: 客户端: import java.io.IOExc ...
- Java实现RS485串口通信,发送和接收数据进行解析
最近项目有一个空气检测仪,需要得到空气检测仪的实时数据,保存到数据库当中.根据了解得到,硬件是通过rs485进行串口通讯的,需要发送16进制命令给仪器,然后通过轮询来得到数据. 需要先要下载RXTX的 ...
- JAVASE02-Unit011: TCP通信(小程序)
TCP通信(小程序) server端: package chat; import java.io.BufferedReader; import java.io.IOException; import ...
- 等待唤醒机制,UDP通信和TCP通信
等待唤醒机制 通过等待唤醒机制使各个线程能有效的利用资源. 等待唤醒机制所涉及到的方法: wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中. notify():唤醒, ...
随机推荐
- ActiveMQ与RabbitMQ的区别
1. ActiveMQ/ApolloMQ 优点:老牌的消息队列,使用Java语言编写.对JMS支持最好,采用多线程并发,资源消耗比较大.如果你的主语言是Java,可以重点考虑. 缺点:由于历史悠久,历 ...
- 在linux下面解压用的zxpf是什么意思,它跟zxvf有啥区别
在linux下面解压用的zxpf是什么意思,它跟zxvf有啥区别 linux 命令中tar后跟的zxvf是什么意思:.tar.gz是一个压缩包 .tar只是打包而没有压缩 z:表示 tar 包是被 ...
- vue init 解决办法
/由于windows系统的某方面问题,vue脚手架安装可能会出现第一证书丢失 // 报错:vue-cli · Failed to download repo vuejs-templates/webpa ...
- kafka常见异常汇总
1>.java.lang.OutOfMemoryError:Map failed 发生上述问题,原因是发生OOM啦,会导致kafka进程直接崩溃掉!因此我们只能重新启动broker节点了,但 ...
- 深入浅出 JavaWeb:Servlet必会必知
一.Web服务器 从事web开发的人,会很清楚一个东西叫HTTP服务器,比如JEE开发—Tomcat,Jetty,.NET开发—ISS等.HTTP服务器是使用 HTTP(超文本传输协议) 与客户机浏览 ...
- sc (service control )
SC 是用来与服务控制管理器和服务进行通信 net: net start 服务名 net stop 服务名 sc: sc config 服务名 start= demand //手动 sc con ...
- 写入MySQL报错超出 max_allowed_packet 的问题
写入MySQL报错超出 max_allowed_packet 的问题. MySQL会根据配置文件会限制server接受的数据包的大小.如果写入大数据时,因为默认的配置太小,插入和更新操作会因为 max ...
- MVC实用架构设计(三)——EF-Code First(1):Repository,UnitOfWork,DbContext
前言 终于到EF了,实在不好意思,最近有点忙,本篇离上一篇发布已经一个多星期了,工作中的小迭代告一段落,终于有点时间来继续我们的架构设计了,在这里先对大家表示歉意. 其实这段时间我并不是把这个系列给忘 ...
- tedu训练营day04
1.猜拳:import randomlist = ['石头','剪刀','布']y = input('''(0) 石头(1) 剪刀(2) 布请出拳(0/1/2):******************* ...
- tomcat下的Cookie特殊符号问题
案例:在项目中通过Cookie方式临时存放检索条件,不小心在Cookie值中使用了特殊符号"@",导致在服务器端无法正确解析Cookie值.之所以说"不小心", ...