基于TCP实现 客户端长连接

一:项目启动即启动设备连接

实现思路:查询表中需要连接的硬件设备,并一一连接,将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;
    }

    //----------------------------------------------------------------------------------------------------------

}

猜你喜欢

转载自blog.csdn.net/gracexiao168/article/details/130347741