基于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;
    }

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

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: C语言中实现基于TCP协议的服务器和客户端通信,需要使用Socket编程。下面是一些基本步骤: 1. 建立服务器 首先需要建立服务器端的socket。通过调用socket()函数创建服务器socket,指定socket的协议族(通常是AF_INET,即IPv4),socket类型(通常是SOCK_STREAM,即TCP流式套接字),和端口号。之后调用bind()函数把服务器socket绑定到指定的地址和端口。接下来就可以调用listen()函数开始监听客户端连接请求。 2. 连接客户端 客户端需要调用socket()函数创建socket,同样指定协议族、socket类型和端口号(这里可以随机指定一个未占用的端口号)。之后调用connect()函数连接服务器的地址和端口号即可。 3. 通信 一旦客户端和服务器端建立连接,就可以通过读写socket进行通信。服务器端需要调用accept()函数接受客户端连接请求,返回一个新的socket描述符用于和客户端进行通信。之后可以使用send()函数向客户端发送数据,使用recv()函数从客户端接收数据。客户端同样可以使用send()和recv()函数进行通信。 4. 结束连接 通信结束后,服务器和客户端需要分别调用close()函数关闭链接。 以上是基于TCP协议的服务器和客户端通信的基本步骤,具体实现过程需要详细的代码实现。在实际开发中,还需要注意处理错误和异常情况,以保证程序的稳定性和安全性。 ### 回答2: 基于TCP协议的服务器和客户端通信是一种常见的网络通讯方式。服务器在网络上侦听特定端口,接收客户端的连接请求。当连接建立后,服务器和客户端之间可以进行数据传输。 实现基于TCP协议的服务器和客户端通信,需要遵循以下步骤: 1. 创建服务器端的套接字(socket)并绑定IP地址和端口号。 2. 监听客户端的连接请求,等待客户端连接。 3. 接受客户端的连接请求,创建一个与客户端通信的套接字。 4. 使用套接字进行数据传输,包括从客户端接收请求和向客户端发送响应。 5. 当通信完成后,关闭连接并释放资源。 对于客户端,需要以下步骤: 1. 创建客户端的套接字。 2. 连接服务器套接字。 3. 发送请求数据给服务器。 4. 接收服务器响应数据。 5. 关闭连接并释放资源。 在实现过程中,还需要注意以下方面: 1. 使用正确的IP地址和端口号进行通信。 2. 服务器端需要使用多线程或多进程进行并发处理,以支持多个客户端同时连接。 3. 通信过程中需要加入一定的数据校验和错误处理机制,以提高通讯的可靠性。 总之,基于TCP协议的服务器和客户端通信是一种灵活、可靠的网络通讯方式,可以广泛应用于各种网络场景中,例如打印、文件传输、远程控制等。 ### 回答3: C 11是一种编程语言,可以用来实现基于TCP的服务器和客户端通信。TCP是传输控制协议的缩写,它提供了一种可靠的数据传输方式,被广泛用于互联网上的通信。 要实现基于TCP的服务器和客户端通信,需要用C 11语言编写两个程序:一个服务器程序和一个客户端程序。服务器程序在运行时监听一个指定的端口,等待客户端程序的连接请求。当客户端请求连接时,服务器程序接受连接请求,并创建一个新的进程或线程用于处理这个连接。 在服务器程序和客户端程序之间进行数据传输时,需要使用TCP协议提供的套接字接口。服务器程序和客户端程序都可以通过套接字接口创建一个套接字,用于进行数据传输。服务器程序可以使用accept函数来接受连接请求,而客户端程序可以使用connect函数来连接服务器。 一旦连接建立,服务器程序和客户端程序之间就可以通过套接字进行数据传输了。服务器程序可以使用send函数将数据发送给客户端程序,而客户端程序可以使用recv函数接收服务器发送的数据。数据传输结束后,服务器程序和客户端程序都可以使用close函数关闭套接字。 总之,用C 11语言编写基于TCP的服务器和客户端通信程序需要了解TCP协议、套接字接口和相应的函数,熟练掌握C 11编程语言,并具有相应的开发经验和编程能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.杨先森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值