提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
测试一个物联网设备,根据通讯协议进行测试
主要目的: 测试命令的正确性和设备的具体功能
提示:以下是本篇文章正文内容,下面案例可供参考
一、通讯方式
首先明确通讯方式:TCP 字节流
连接方式: 我们使用的网线,也可以使用RS485或者无线模块,网线最方便快捷、稳定且成本低
测试设备为客户端,我需要写一个服务端来进行交互通信
命令格式:十六进制数转字节流,字节流转十六进制数(帧格式采用CS校验)
二、具体实现
1.配置设备
吐槽一下:
厂家支持不是很友好,沟通效率差。
没有准确的说明书,最后才弄明白具体的操作和方案
在设备上配置好ip、端口、网关等网络配置
2.接收客户端的信息
接收客户端的消息,我首先使用了一个测试工具,发现设备一直有正常上报信息,才开始写的。也是确保设备能正常通讯。
明确自己是服务端、接收的信息为字节流
需要一直启动线程,确保可以一直接收到客户端传过来的信息
主动向客户端发送字节流
代码如下(示例):
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import org.json.JSONObject
public class ServerThread extends Thread {
Socket socket = null;
InetAddress inetAddress=null;//接收客户端的连接
public ServerThread(Socket socket,InetAddress inetAddress) {
this.socket = socket;
this.inetAddress=inetAddress;
}
@Override
public void run() {
new sendMessThread().start();//连接并返回socket后,再启用发送消息线程
InputStream inputStream = null;//字节输入流
InputStreamReader inputStreamReader = null;//将一个字节流中的字节解码成字符
BufferedReader bufferedReader = null;//为输入流添加缓冲
OutputStream outputStream = null;//字节输出流
OutputStreamWriter writer = null;//将写入的字符编码成字节后写入一个字节流
try {
//封装输入流(接收客户端的字节流)
BufferedInputStream bis = new BufferedInputStream(
socket.getInputStream());
DataInputStream dis = new DataInputStream(bis);
byte[] bytes = new byte[1]; // 一次读取一个byte
String ret = "";
while (dis.read(bytes) != -1) {
ret += bytesToHexString(bytes) + " ";
if (dis.available() == 0) { //一个请求
System.out.println(socket.getRemoteSocketAddress() + ":" + ret);
ret = "";
}
}
//这里定义的是原来接收json的
// inputStream = socket.getInputStream();
// inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
// bufferedReader = new BufferedReader(inputStreamReader);
// String info = null;//临时
//
// //循环读取客户端信息
// while ((info = bufferedReader.readLine()) != null) {
// //获取客户端的ip地址及发送数据
// System.out.println("服务器端接收:"+"{'from_client':'"+socket.getInetAddress().getHostAddress()+"','data':'"+info+"'}");
// }
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
try {
if (writer != null) {
writer.close();
}
if (outputStream != null) {
outputStream.close();
}
if (bufferedReader != null) {
bufferedReader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class sendMessThread extends Thread{
@Override
public void run(){
super.run();
Scanner scanner=null;
OutputStream out = null;
try{
if(socket != null){
scanner = new Scanner(System.in);
out = socket.getOutputStream();
String in = "";
do {
in = scanner.next();
byte[] hex2Byte = hex2Byte(in.replace(" ", ""));
out.write(hex2Byte);
out.flush();//清空缓存区的内容
}while (!in.equals("q"));
scanner.close();
try{
out.close();
}catch (IOException e){
e.printStackTrace();
}
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 将16进制字符转换成byte[]数组。与byte2Hex功能相反。
* @param string 16进制字符串
* @return byte[]数组
*/
public static byte[] hex2Byte(String string) {
if (string == null || string.length() < 1) {
return null;
}
// 因为一个byte生成两个字符,长度对应1:2,所以byte[]数组长度是字符串长度一半
byte[] bytes = new byte[string.length() / 2];
// 遍历byte[]数组,遍历次数是字符串长度一半
for (int i = 0; i < string.length() / 2; i++) {
// 截取没两个字符的前一个,将其转为int数值
int high = Integer.parseInt(string.substring(i * 2, i * 2 + 1), 16);
// 截取没两个字符的后一个,将其转为int数值
int low = Integer.parseInt(string.substring(i * 2 + 1, i * 2 + 2), 16);
// 高位字符对应的int值*16+低位的int值,强转成byte数值即可
// 如dd,高位13*16+低位13=221(强转成byte二进制11011101,对应十进制-35)
bytes[i] = (byte) (high * 16 + low);
}
return bytes;
}
/**
* byte[]数组转换为16进制的字符串
*
* @param bytes 要转换的字节数组
* @return 转换后的结果
*/
public static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
}
代码如下(示例):
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(1111);//创建绑定到特定端口的服务器Socket。
Socket socket = null;//需要接收的客户端Socket
int count = 0;//记录客户端数量
System.out.println("服务器启动");
//定义一个死循环,不停的接收客户端连接
while (true) {
socket = serverSocket.accept();//侦听并接受到此套接字的连接
// new sendMessThread().start();//连接并返回socket后,再启用发送消息线程
InetAddress inetAddress=socket.getInetAddress();//获取客户端的连接
ServerThread thread=new ServerThread(socket,inetAddress);//自己创建的线程类
thread.start();//启动线程
count++;//如果正确建立连接
System.out.println("客户端数量:" + count);//打印客户端数量
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
总结
测试用的内容,希望后面项目一切顺利
使用效果图: