一:项目启动即启动设备连接
实现思路:查询表中需要连接的硬件设备,并一一连接,将socket放在redis中
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Component
@Configuration
@Slf4j
@Order(value = 1)
public class ConnectServerImpl implements CommandLineRunner {
public static final Map<Integer, Socket> CONNECT_MAP = new HashMap<>();
public void decoyConnect(){
log.info("开始连接设备");
List<DemoPo> demoPos =
Objects.requireNonNull(BeanFactory.getBean(DemoMapper.class))
.selectList(new LambdaUpdateWrapper<DemoPo>()
.eq(DemoPo::getRunStatus, 1)
.eq(DemoPo::getDeleteFlag, 1));
for(DemoPo demo : demoPos ) {
connect(demo );
}
}
public static Socket connect(DemoPo demo) {
Socket socket = TcpClient.connect(demo.getIpAddress(), demo.getPort());
CONNECT_MAP.put(demo.getId(), socket);
return socket;
}
public static void closeSocket(demo po, Socket socket) {
try {
socket.close();
} catch (IOException e) {
log.error("设备" + po.getEquipmentName() + "已离线", e);
}
}
@Override
public void run(String... args){
decoyConnect();
}
}
二:干货 连接工具类
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Map;
@Slf4j
public class TcpClient {
public static Socket connect(String ip, Integer port) {
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(ip, port), 3000);
log.info("设备连接成功");
} catch (Exception e) {
log.error("设备连接异常", e);
}
return socket;
}
public static String sendMessage(Socket socket, String msg) {
String re = "";
try {
OutputStream outputStream = socket.getOutputStream();
for (int i = 0; i < 2; i++) {
byte[] byteArray = hexStrToByteArray(msg);
outputStream.write(byteArray);
outputStream.flush();
//得到一个输入流,用于接收服务器响应的数据
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1]; // 一次读取一个byte
StringBuilder info = new StringBuilder();
while (inputStream.read(bytes) > 0) {
String hexStr = byteArrayToHexStr(bytes);
info.append(hexStrToStr(hexStr));
//已经读完
if (inputStream.available() == 0) {
log.info("收到来自服务端的信息:" + str2HexStr(info.toString()));
re = str2HexStr(info.toString());
break;
}
}
}
} catch (Exception e) {
log.error("发送消息异常", e);
}
return re;
}
public static String startClient(String host, int port, String msg) {
String re = "";
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(host, port), 3000);
//得到一个输出流,用于向服务器发送数据
OutputStream outputStream = socket.getOutputStream();
for (int i = 0; i < 2; i++) {
byte[] byteArray = hexStrToByteArray(msg);
outputStream.write(byteArray);
outputStream.flush();
//得到一个输入流,用于接收服务器响应的数据
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1]; // 一次读取一个byte
StringBuilder info = new StringBuilder();
while (inputStream.read(bytes) > 0) {
String hexStr = byteArrayToHexStr(bytes);
info.append(hexStrToStr(hexStr));
//已经读完
if (inputStream.available() == 0) {
log.info("收到来自服务端的信息:" + str2HexStr(info.toString()));
re = str2HexStr(info.toString());
break;
}
}
outputStream.flush();
}
outputStream.close();
} catch (Exception e) {
log.error("send message error", e);
} finally {
try {
socket.close();
} catch (Exception e) {
log.error("tcp connect off error", e);
}
}
return re;
}
public static String str2HexStr(String str) {
char[] chars = "0123456789ABCDEF".toCharArray();
StringBuilder sb = new StringBuilder();
byte[] bs = str.getBytes();
int bit;
for (byte b : bs) {
bit = (b & 0x0f0) >> 4;
sb.append(" ").append(chars[bit]);
bit = b & 0x0f;
sb.append(chars[bit]);
}
return sb.toString().trim();
}
/**
* 16进制Str转byte[]
*/
public static byte[] hexStrToByteArray(String hexStr) {
if (hexStr == null) {
return new byte[0];
}
if (hexStr.length() == 0) {
return new byte[0];
}
byte[] byteArray = new byte[hexStr.length() / 2];
for (int i = 0; i < byteArray.length; i++) {
String subStr = hexStr.substring(2 * i, 2 * i + 2);
byteArray[i] = ((byte) Integer.parseInt(subStr, 16));
}
return byteArray;
}
/**
* byte[]转16进制Str
*/
public static String byteArrayToHexStr(byte[] byteArray) {
if (byteArray == null) {
return null;
}
char[] hexArray = "0123456789ABCDEF".toCharArray();
char[] hexChars = new char[byteArray.length * 2];
for (int i = 0; i < byteArray.length; i++) {
int temp = byteArray[i] & 0xFF;
hexChars[i * 2] = hexArray[temp >>> 4];
hexChars[i * 2 + 1] = hexArray[temp & 0x0F];
}
return new String(hexChars);
}
/**
* 16进制的Str转Str
*/
public static String hexStrToStr(String hexStr) {
//能被16整除,肯定可以被2整除
byte[] array = new byte[hexStr.length() / 2];
try {
for (int i = 0; i < array.length; i++) {
array[i] = (byte) (0xff & Integer.parseInt(hexStr.substring(i * 2, i * 2 + 2), 16));
}
hexStr = new String(array, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
return "";
}
return hexStr;
}
}
三:赠送一个工具类
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* 本工具类用于16进制转 经纬度
*/
@Slf4j
public class NumberUtil {
public static void main(String[] args) {
double v = readDouble(byte2Byffer(bytes), 8, ByteOrder.LITTLE_ENDIAN);
System.out.println(v);
}
public static ByteBuffer byte2Byffer(byte[] byteArray) {
//初始化一个和byte长度一样的buffer
ByteBuffer buffer=ByteBuffer.allocate(byteArray.length);
// 数组放到buffer中
buffer.put(byteArray);
//重置 limit 和postion 值 否则 buffer 读取数据不对
buffer.flip();
return buffer;
}
public static byte[] toByteArray(String arg) {
if (arg != null) {
char[] newArray = new char[1000];
char[] array = arg.toCharArray();
int length = 0;
for (char c : array) {
if (c != ' ') {
newArray[length] = c;
length++;
}
}
int evenLength = (length % 2 == 0) ? length : length + 1;
if (evenLength != 0) {
int[] data = new int[evenLength];
data[evenLength - 1] = 0;
for (int i = 0; i < length; i++) {
if (newArray[i] >= '0' && newArray[i] <= '9') {
data[i] = newArray[i] - '0';
} else if (newArray[i] >= 'a' && newArray[i] <= 'f') {
data[i] = newArray[i] - 'a' + 10;
} else if (newArray[i] >= 'A' && newArray[i] <= 'F') {
data[i] = newArray[i] - 'A' + 10;
}
}
byte[] byteArray = new byte[evenLength / 2];
for (int i = 0; i < evenLength / 2; i++) {
byteArray[i] = (byte) (data[i * 2] * 16 + data[i * 2 + 1]);
}
return byteArray;
}
}
return new byte[] {};
}
public static byte[] hexStringToBytes(String hex) {
byte[] bytes = new byte[hex.length() / 2];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
}
return bytes;
}
public static double getBigDecimal(String tpc16) {
//10 进制数
int num = Integer.parseInt(tpc16.replaceAll("\\s*", ""), 16);
BigDecimal d = BigDecimal.valueOf((float) num / 30000).setScale(5, RoundingMode.HALF_UP);
String s = String.valueOf(d);
int i = Integer.parseInt(s.substring(0, s.indexOf(".")));
//度数
long dd = i / 60;
//分秒
double bigDecimal = d.subtract(BigDecimal.valueOf(dd * 60)).setScale(5, RoundingMode.HALF_UP).doubleValue();
double v = bigDecimal / 60;
double decimal = BigDecimal.valueOf(v).setScale(5, RoundingMode.HALF_UP).doubleValue();
return dd + decimal;
}
/*
* 大小端数据转换
*/
public static String lockAddress(String lockAddress) {
StringBuilder s1 = new StringBuilder(lockAddress);
int index;
for (index = 2; index < s1.length(); index += 3) {
s1.insert(index, ',');
}
String[] array = s1.toString().split(",");
String[] swapOrder = swapOrder(array);
StringBuilder s2 = new StringBuilder();
for (String string : swapOrder) {
s2.append(string);
}
return s2.toString();
}
public static String[] swapOrder(String[] arr) {
int length = arr.length;
for (int i = 0; i < length / 2; i++) { //只需一个循环,数组的一半就可以,第一个和最后一个交换,第二个和倒数第二个交换。。。
String temp = arr[i];
arr[i] = arr[length - 1 - i];
arr[length - 1 - i] = temp;
}
return arr;
}
/** 16进制转Double */
public static double readDouble(ByteBuffer buffer, int bytes, ByteOrder byteOrder) {
ByteBuffer byteBuffer = readType(Double.BYTES, buffer, bytes, byteOrder);
return byteBuffer.getDouble();
}
public static ByteBuffer readType(int typeLength, ByteBuffer buffer, int bytes, ByteOrder byteOrder) {
byte[] ba = new byte[bytes];
buffer.get(ba);
ByteBuffer byteBuffer = ByteBuffer.allocate(typeLength);
int padLength = typeLength - bytes;
for (int i = 0; i < padLength; i++) {
byteBuffer.put((byte) 0);
}
if (byteOrder.equals(ByteOrder.LITTLE_ENDIAN)) {
for (int i = ba.length - 1; i >= 0; i--) {
byteBuffer.put(ba[i]);
}
} else {
for (byte b : ba) {
byteBuffer.put(b);
}
}
byteBuffer.position(0);
return byteBuffer;
}
//------------------------------根据坐标点判断在不在多边形内-----------------------------------------------------------
// public static void main(String[] args) {
// // 被检测的经纬度点
// String x="116.377872";
// String y="39.911031";
// // 商业区域(百度多边形区域经纬度集合)
// String partitionLocation = "116.377679_39.911113,116.378052_39.911085,116.378047_39.910933,116.377679_39.910937";
// System.out.println(isInPolygon(x,y,partitionLocation));
// }
/**
* 判断当前位置是否在多边形区域内
* @param partitionLocation 区域顶点
*/
public static boolean isInPolygon(String x,String y,String partitionLocation){
double pX =Double.parseDouble(x);
double pY =Double.parseDouble(y);
Point2D.Double point = new Point2D.Double(pX, pY);
List<Point2D.Double> pointList= new ArrayList<>();
String[] strList = partitionLocation.split(",");
for (String str : strList){
String[] points = str.split("_");
double polygonPointX=Double.parseDouble(points[0]);
double polygonPointY=Double.parseDouble(points[1]);
Point2D.Double polygonPoint = new Point2D.Double(polygonPointX,polygonPointY);
pointList.add(polygonPoint);
}
return isPtInPoly(point,pointList);
}
/**
* 判断点是否在多边形内,如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
* @param point 检测点
* @param pts 多边形的顶点
* @return 点在多边形内返回true,否则返回false
*/
public static boolean isPtInPoly(Point2D.Double point, List<Point2D.Double> pts){
int n = pts.size();
boolean boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
int intersectCount = 0;//cross points count of x
double precision = 2e-10; //浮点类型计算时候与0比较时候的容差
Point2D.Double p1;
Point2D.Double p2;
p1 = pts.get(0);//left vertex
for(int i = 1; i <= n; ++i){//check all rays
if(point.equals(p1)){
return boundOrVertex;//p is an vertex
}
p2 = pts.get(i % n);
if(point.x < Math.min(p1.x, p2.x) || point.x > Math.max(p1.x, p2.x)){
p1 = p2;
continue;
}
if(point.x > Math.min(p1.x, p2.x) && point.x < Math.max(p1.x, p2.x)){
if(point.y <= Math.max(p1.y, p2.y)){
if(p1.x == p2.x && point.y >= Math.min(p1.y, p2.y)){
return boundOrVertex;
}
if(p1.y == p2.y){
if(p1.y == point.y){
return boundOrVertex;
}else{//before ray
++intersectCount;
}
}else{
double xinters = (point.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
if(Math.abs(point.y - xinters) < precision){
return boundOrVertex;
}
if(point.y < xinters){
++intersectCount;
}
}
}
}else{
if(point.x == p2.x && point.y <= p2.y){
Point2D.Double p3 = pts.get((i+1) % n);
if(point.x >= Math.min(p1.x, p3.x) && point.x <= Math.max(p1.x, p3.x)){
++intersectCount;
}else{
intersectCount += 2;
}
}
}
p1 = p2;
}
//偶数在多边形外
//奇数在多边形内
return intersectCount % 2 != 0;
}
//----------------------------------------------------------------------------------------------------------
}