IPV6 阿里DDNS

2023-11-12

IPV6 阿里DDNS

因为需要在家搭建一套环境,并且需要公网能访问。国内的ipv4的地址,各大运营商基本都不会分配ipv4地址(电信宽带好像有地方可以,但是听说很贵),而且是动态的,每过段时间就会改变。
  发现移动宽带的公网ipv6地址是可以获取到的,但是也会动态刷新。想稳定访问就加上阿里的ddns的域名访问。
  有时候电脑的mac地址在路由器注册上,公网会访问不了。我也不知道是什么原因。但是晚上凌晨4点或者5点时候定时重启路由器,基本上就没问题。

1.改光猫信息和设置路由器拨号

因为宽带接入家里基本是都是需要通过光猫拨号后,再接入路由器。这样就拿不到真实的公网ipv6地址,需要先将光猫中的设置改为桥接模式,再让路由器输入宽带账户和密码拨号。
  改光猫和路由器这个步骤,确实很多坑,需要看网上的很多教程。光猫的型号和地区不一样,设置的方式也不一样,所以这一步就不详细介绍。

2.准备阿里云域名和获取阿里开发AccessKeyID和AccessKeySecret

2.1 准备域名

注册一个阿里云账号,购买域名,可以买个比较便宜的一级域名。购买完成后
在这里插入图片描述
在这里插入图片描述
购买以后需要看看dns服务器设置是否成功。阿里免费的ddns解析,修改ip后,大概10分钟左右生效。
然后进入左侧的 “域名解析” 菜单
在这里插入图片描述
主机记录是二级域名前缀,@表示是主域名
记录类型 A是ipv4地址 AAAA是ipv6地址
TTL 生效时间

2.2 获取阿里开发AccessKeyID和AccessKeySecret

在这里插入图片描述

3.开始脚本项目

3.1 引入阿里的sdk包

引入阿里现成的maven包,里面封装好的接口

 <dependencies>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-alidns</artifactId>
            <version>2.0.10</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.3.2</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.12</version>
        </dependency>
    </dependencies>
3.2 加载配置信息

域名,AccessKeyID和AccessKeySecret

初始化下配置信息

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

import java.io.*;
import java.nio.charset.StandardCharsets;


public class Config {
    //这读取的是json文件配置,也可以直接输入域名,AccessKeyID,和AccessKeySecret
    public static  String host="";

    public static  String AccessKeyID="";

    public static  String AccessKeySecret="";

    public static void initConfig(){
        if(StrUtil.isNotBlank(host) && StrUtil.isNotBlank(AccessKeyID) && StrUtil.isNotBlank(AccessKeySecret)){
            LogUtil.logOut("host:"+host);
            LogUtil.logOut("AccessKeyID:"+AccessKeyID);
            LogUtil.logOut("AccessKeySecret:"+AccessKeySecret);
            return;
        }
        String jarPath= System.getProperty("user.dir");
        System.out.println(jarPath);
        File file=new File(jarPath+File.separator+"config.json");

        if(!file.exists()){
            LogUtil.logOut("initConfig config.json文件不存在");
            return;
        }
        JSONObject json= JSONUtil.readJSONObject(file, StandardCharsets.UTF_8);
        String host=json.getStr("host");
        String AccessKeyID=json.getStr("AccessKeyID");
        String AccessKeySecret=json.getStr("AccessKeySecret");
        if(StrUtil.isBlank(host) || StrUtil.isBlank(AccessKeyID) || StrUtil.isBlank(AccessKeySecret)){
            LogUtil.logOut("参数配置出现问题!!!!!!!!");
            throw new RuntimeException("参数配置出现问题!!!!!!!!");
        }
        Config.host=host;
        Config.AccessKeyID=AccessKeyID;
        Config.AccessKeySecret=AccessKeySecret;
    }
}


3.3 获取服务器ipv6地址


import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author liu
 * @time 2021/11/1
 * @description
 */
public class IPv6 {

    private static final CopyOnWriteArrayList<String> ipv6s = new CopyOnWriteArrayList<>();

    //随机数
    static Random random = new Random();
    static {
        // 创建定时器任务
        Executors.newScheduledThreadPool(1).scheduleWithFixedDelay(() -> refreshIps(),1,60,TimeUnit.SECONDS);
    }



    private static synchronized void refreshIps() {
        LogUtil.logOut("开始刷新ip");
        try {
            List<String> getIpv6s = getLocalIPv6Address();
            if (getIpv6s.isEmpty()) {
                return;
            }
            List<String> temp=new ArrayList<>();
            List<String> finalTemp = temp;
            getIpv6s.forEach(ip -> {
                try {
                    if (pingTest(ip)) {
                        finalTemp.add(ip);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            });
            ipv6s.clear();
            temp= temp.stream().distinct().collect(Collectors.toList());
            ipv6s.addAll(temp);
            if (ipv6s.isEmpty()) {
                ipv6s.addAll(getIpv6s);
            }
        } catch (Exception e) {
           e.printStackTrace();
        }
        LogUtil.logOut("结束刷新ip");
    }

    public static String getNextId(){
        if(ipv6s.isEmpty()){
            refreshIps();
        }
        if(ipv6s.isEmpty()){
            return "";
        }
        int i2 = random.nextInt(1000);
        int flag=i2%ipv6s.size();
        return ipv6s.get(flag);
    }

    public static List<String> getLocalIPv6Address() throws SocketException {
        InetAddress inetAddress = null;
        List<String> ipv6s = new ArrayList<>();
        Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
        while (networkInterfaces.hasMoreElements()) {
            Enumeration<InetAddress> inetAds = networkInterfaces.nextElement().getInetAddresses();
            while (inetAds.hasMoreElements()) {
                inetAddress = inetAds.nextElement();
                //检查此地址是否是IPv6地址以及是否是保留地址
                if (inetAddress instanceof Inet6Address && !isReservedAddr(inetAddress)) {
                    String ipAddr = inetAddress.getHostAddress();
                    //过滤网卡
                    int index = ipAddr.indexOf('%');
                    if (index > 0) {
                        ipAddr = ipAddr.substring(0, index);
                    }
                    ipv6s.add(ipAddr);
                }
            }
        }
        LogUtil.log_print("ip数据",ipv6s);
        return ipv6s;
    }


    private static boolean isReservedAddr(InetAddress inetAddr) {
        if (inetAddr.isAnyLocalAddress() || inetAddr.isLinkLocalAddress() || inetAddr.isLoopbackAddress()) {
            return true;
        }
        return false;
    }

    public static boolean ping(String ipAddress, int pingTimes) {
        BufferedReader in = null;
        // 将要执行的ping命令,此命令是windows格式的命令
        Runtime r = Runtime.getRuntime();
        //String pingCommand = "ping " + ipAddress + " -n " + pingTimes    + " -w " + timeOut;
        String pingCommand = "ping6 " + ipAddress + " -c " + pingTimes;

        try {   // 执行命令并获取输出
            LogUtil.logOut(pingCommand);
            Process p = r.exec(pingCommand);
            if (p == null) {
                return false;
            }
            // 逐行检查输出,计算类似出现=23ms TTL=62字样的次数
            in = new BufferedReader(new InputStreamReader(p.getInputStream()));
            int connectedCount = 0;
            String line = null;
            while ((line = in.readLine()) != null) {
                connectedCount += getCheckResult(line);
            }   // 如果出现类似=23ms TTL=62这样的字样,出现的次数=测试次数则返回真
            return connectedCount >= pingTimes;
        } catch (Exception ex) {
            ex.printStackTrace();   // 出现异常则返回假
            return false;
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 用外网测试网站来测试https://ipw.cn/api/ping/ipv6
     */
    private static boolean pingTest(String ipaddr) {
        String pingAddr = String.format("https://ipw.cn/api/ping/ipv6/%s/4/all", ipaddr);
        String reStr = HttpURLConnectionUtil.doGet(pingAddr);
        JSONObject json = JSONUtil.parseObj(reStr);
        JSONArray jsonArray = json.getJSONArray("pingResultDetail");
        for (Object jsonr : jsonArray) {
            JSONObject jsonResult = (JSONObject) jsonr;
            Boolean result = jsonResult.getBool("result");
            if (result) {
                return true;
            }
        }
        return false;
    }

    /**
     * 若line含有=18ms TTL=16字样,说明已经ping通,返回1,否則返回0.
     */
    private static int getCheckResult(String line) {
        LogUtil.logOut("控制台输出的结果为:" + line);
        String[] lines = line.split("=");
        String lessStr = lines[lines.length - 1].split(" ")[0];
        try {

            if (line.contains("Unreachable")) {
                return 0;
            }
            if (line.contains("unreachable")) {
                return 0;
            }
            if (Double.valueOf(lessStr) > 0) {
                return 1;
            }
        } catch (Exception e) {
            return 0;
        }
        return 0;
    }


}


3.4 main启动类
import cn.hutool.core.util.StrUtil;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.alidns.model.v20150109.*;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;


import java.io.IOException;
import java.net.SocketException;

import java.util.List;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class DDNS {

    /**
     * 获取主域名的所有解析记录列表
     */
    private DescribeSubDomainRecordsResponse describeSubDomainRecords(DescribeSubDomainRecordsRequest request, IAcsClient client) {
        try {
            // 调用SDK发送请求
            return client.getAcsResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
            // 发生调用错误,抛出运行时异常
            throw new RuntimeException();
        }
    }

    /**
     * 修改解析记录
     */
    private UpdateDomainRecordResponse updateDomainRecord(UpdateDomainRecordRequest request, IAcsClient client) {
        try {
            //  调用SDK发送请求
            return client.getAcsResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
            //  发生调用错误,抛出运行时异常
            throw new RuntimeException();
        }
    }

    /**
     * 修改解析记录
     */
    private AddDomainRecordResponse addDomainRecord(AddDomainRecordRequest request, IAcsClient client) {
        try {
            //  调用SDK发送请求
            return client.getAcsResponse(request);
        } catch (ClientException e) {
            e.printStackTrace();
            //  发生调用错误,抛出运行时异常
            throw new RuntimeException();
        }
    }


    public static void main(String[] args) {
        Config.initConfig();
        //  设置鉴权参数,初始化客户端
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou",// 地域ID
                Config.AccessKeyID,// 您的AccessKey ID
                Config.AccessKeySecret);// 您的AccessKey Secret
        IAcsClient client = new DefaultAcsClient(profile);

        // 创建定时器任务
        Executors.newScheduledThreadPool(1).scheduleWithFixedDelay(() -> {
            try {
                ddnsOp(client);
            } catch (Exception e) {
                e.printStackTrace();
                LogUtil.logOut(e.getMessage());
            }
        }, 1, 300, TimeUnit.SECONDS);
    }

    private static void ddnsOp(IAcsClient client) {
        DDNS ddns = new DDNS();

        //查询指定二级域名的最新解析记录
        DescribeSubDomainRecordsRequest describeSubDomainRecordsRequest = new DescribeSubDomainRecordsRequest();
        describeSubDomainRecordsRequest.setSubDomain(Config.host);
        DescribeSubDomainRecordsResponse describeSubDomainRecordsResponse = ddns.describeSubDomainRecords(describeSubDomainRecordsRequest, client);
        LogUtil.log_print("describeSubDomainRecords", describeSubDomainRecordsResponse);

        List<DescribeSubDomainRecordsResponse.Record> domainRecords = describeSubDomainRecordsResponse.getDomainRecords();
        //最新的一条解析记录
        if (domainRecords.size() != 0) {

            DescribeSubDomainRecordsResponse.Record record = domainRecords.get(0);
            //  记录ID
            String recordId = record.getRecordId();
            //  记录值
            String recordsValue = record.getValue();
            //  当前主机公网IP
            String currentHostIP = IPv6.getNextId();

            if (StrUtil.isBlank(currentHostIP)) {
                LogUtil.logOut("----------无法获取到主机ip-----------");
                return;
            }
            LogUtil.logOut("-------------------------------当前主机公网IP为:" + currentHostIP + "-------------------------------");
            if (!currentHostIP.equals(recordsValue)) {
                LogUtil.logOut("-------------------------------当前主机公网IP不一致,开始修改-------------------------------");
                //  修改解析记录
                UpdateDomainRecordRequest updateDomainRecordRequest = new UpdateDomainRecordRequest();
                //  主机记录
                updateDomainRecordRequest.setRR("@");
                //  记录ID
                updateDomainRecordRequest.setRecordId(recordId);
                //  将主机记录值改为当前主机IP
                updateDomainRecordRequest.setValue(currentHostIP);
                //  解析记录类型
                updateDomainRecordRequest.setType("AAAA");
                UpdateDomainRecordResponse updateDomainRecordResponse = ddns.updateDomainRecord(updateDomainRecordRequest, client);
                LogUtil.log_print("updateDomainRecord", updateDomainRecordResponse);
                LogUtil.logOut("-------------------------------修改结束-------------------------------");
            }else {
                LogUtil.logOut("-------------------------------当前主机公网IP一致,不需要修改-------------------------------");
            }

        } else {

            //  当前主机公网IP
            String currentHostIP = IPv6.getNextId();
            //  当前主机公网IP
            if (StrUtil.isBlank(currentHostIP)) {
                LogUtil.logOut("----------无法获取到主机ip-----------");
                return;
            }
            LogUtil.logOut("-------------------------------当前主机公网IP为:" + currentHostIP + "-------------------------------");
            AddDomainRecordRequest addDomainRecordRequest = new AddDomainRecordRequest();
            addDomainRecordRequest.setDomainName(Config.host);
            addDomainRecordRequest.setRR("@");
            //  将主机记录值改为当前主机IP
            addDomainRecordRequest.setValue(currentHostIP);
            //  解析记录类型
            addDomainRecordRequest.setType("AAAA");
            AddDomainRecordResponse updateDomainRecordResponse = ddns.addDomainRecord(addDomainRecordRequest, client);
            LogUtil.log_print("updateDomainRecord", updateDomainRecordResponse);
        }
    }
}
3.5 config.json配置文件
***这个配置文件需要和jar包同级目录***
  {
	"host":"ljXXXX.top",
	"AccessKeyID":"LTAI5tPXXXXXXX",
	"AccessKeySecret":"FhkXXXXXX"
}
3.6 ipv6线上测试工具

import com.sun.istack.Nullable;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;


/**
 * @Author: liu
 * @Description: http工具
 * @Date: 2023/3/3 15:20
 */
public class HttpURLConnectionUtil {
    /**
     * http get请求
     * @param httpUrl 链接
     * @return 响应数据
     */
    public static String doGet(String httpUrl){
        //链接
        HttpURLConnection connection=null;
        InputStream is=null;
        BufferedReader br = null;
        StringBuffer result=new StringBuffer();
        try {
            //创建连接
            URL url=new URL(httpUrl);
            connection= (HttpURLConnection) url.openConnection();
            //设置请求方式
            connection.setRequestMethod("GET");
            //设置连接超时时间
            connection.setConnectTimeout(3000);
            //设置读取超时时间
            connection.setReadTimeout(3000);
            //开始连接
            connection.connect();
            //获取响应数据
            if(connection.getResponseCode()==200){
                //获取返回的数据
                is=connection.getInputStream();
                if(is!=null){
                    br=new BufferedReader(new InputStreamReader(is,"UTF-8"));
                    String temp = null;
                    while ((temp=br.readLine())!=null){
                        result.append(temp);
                    }
                }
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }finally {
            if(br!=null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            connection.disconnect();// 关闭远程连接
        }
        return result.toString();
    }

    /**
     * post请求
     * @param httpUrl 链接
     * @param param 参数
     * @return
     */
    public static String doPost(String httpUrl, @Nullable String param) {
        StringBuffer result=new StringBuffer();
        //连接
        HttpURLConnection connection=null;
        OutputStream os=null;
        InputStream is=null;
        BufferedReader br=null;
        try {
            //创建连接对象
            URL url=new URL(httpUrl);
            //创建连接
            connection= (HttpURLConnection) url.openConnection();
            //设置请求方法
            connection.setRequestMethod("POST");
            //设置连接超时时间
            connection.setConnectTimeout(15000);
            //设置读取超时时间
            connection.setReadTimeout(15000);
            //设置是否可读取
            connection.setDoOutput(true);
            //设置响应是否可读取
            connection.setDoInput(true);
            //设置参数类型
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            //拼装参数
            if(param!=null&&!param.equals("")){
                //设置参数
                os=connection.getOutputStream();
                //拼装参数
                os.write(param.getBytes("UTF-8"));
            }
            //设置权限
            //设置请求头等
            //开启连接
            //connection.connect();
            //读取响应
            if(connection.getResponseCode()==200){
                is=connection.getInputStream();
                if(is!=null){
                    br=new BufferedReader(new InputStreamReader(is,"UTF-8"));
                    String temp=null;
                    if((temp=br.readLine())!=null){
                        result.append(temp);
                    }
                }
            }
            //关闭连接
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(br!=null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //关闭连接
            connection.disconnect();
        }
        return result.toString();
    }

}

3.7 日志输出

import com.google.gson.Gson;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;


/**
 * @author fancy
 */
public class LogUtil {
    private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
    public static void logOut(Object info){
        String threadName=Thread.currentThread().getName();
        System.out.println(dtf.format(LocalDateTime.now())+"--线程名"+threadName+":::"+info);
    }
    public static void log_print(String functionName, Object result) {
        Gson gson = new Gson();
        LogUtil.logOut("-------------------------------" + functionName + "-------------------------------");
        LogUtil.logOut(gson.toJson(result));
    }
}

3.7 使用脚本

aliDDns.sh 启动

#!/bin/bash

APP_NAME=aliDDns-1.0-SNAPSHOT.jar

#使用说明,用来提示输入参数
usage() {
    echo "Usage: sh 脚本名.sh [start|stop|restart|status]"
    exit 1
}

#检查程序是否在运行
is_exist(){
  pid=`ps -ef|grep $APP_NAME|grep -v grep|awk '{print $2}' `
  #如果不存在返回1,存在返回0
  if [ -z "${pid}" ]; then
    return 1
  else
    return 0
  fi
}

#启动方法
start(){
  is_exist
  if [ $? -eq "0" ]; then
    echo "${APP_NAME} is already running. pid=${pid} ."
  else
    #启动时设置并发垃圾收集器
    nohup java -Xms64m -Xmx64m -XX:MetaspaceSize=16m -XX:MaxMetaspaceSize=32m -cp  ./target/$APP_NAME DDNS > log.file 2>&1 &
    echo "${APP_NAME} start success"
  fi
}

#停止方法
# shellcheck disable=SC2120
stop(){
  is_exist
  if [ $? -eq "0" ]; then
    PROCESS=`ps -ef|grep $APP_NAME|grep -v grep|grep -v PPID|awk '{ print $2}'`
    for i in $PROCESS
    do
      echo "Kill the $1 process [ $i ]"
      kill -9 $i
    done
  else
    echo "${APP_NAME} is not running"
  fi
}

#输出运行状态
status(){
  is_exist
  if [ $? -eq "0" ]; then
    echo "${APP_NAME} is running. Pid is ${pid}"
  else
    echo "${APP_NAME} is NOT running."
  fi
}

#重启
restart(){
  stop
  start
}

#根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
  "start")
    start
    ;;
  "stop")
    stop
    ;;
  "status")
    status
    ;;
  "restart")
    restart
    ;;
  *)
    usage
    ;;
esac



总结

如果不是做java研发,这个脚本跑起来有点难。这个是打包好的
打包好的zip文件 ,所有文件放在同级目录,或者改下shell脚本中的路径也行

用过一段时间后发现还是有问题,又加了检测方式和更新ip方式,建议把阿里的域名解析通知给关了,不然会频繁发送邮件或者通知。

如果没有积分可留言
代码地址源码 代码有更新,文章的代码已经过时

声明:该项目只是做个人学习使用,并未将域名暴露他人。网友其他行为与本人无关!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IPV6 阿里DDNS 的相关文章

  • mvp关联activity生命周期_Android MVP架构从入门到精通-真枪实弹

    Android MVP架构从入门到精通 真枪实弹 一 前言 你是否遇到过Activity Fragment中成百上千行代码 完全无法维护 看着头疼 你是否遇到过因后台接口还未写而你不能先写代码逻辑的情况 你是否遇到过用MVC架构写的项目进行
  • VMware Workstation 16 Player 安装Centos 7

    环境准备 VMware Workstation 16 Player 官方下载 https www vmware com products workstation player workstation player evaluation ht
  • Cesium 源码解析 Model(一)

    Cesium中对于3DTiles会解析成Model 特别是3DTile中的B3DM 过程主要是对gltf在Cesium中是如何解析并生成绘制命令的 content model new Model gltf gltfView gltf数据 c
  • 全球数字治理白皮书 附下载

    当今世界 科技革命和产业变革日新月异 数字经济蓬勃发展 深刻改变着人类生产生活方式 对各国经济社会发展 全球治理体系 人类文明进程影响深远 在经济全球化遭遇逆流 保护主义 单边主 义上升的背景下 数字化驱动的新一轮全球化仍蓬勃发展 已成为助

随机推荐

  • QT学习笔记(七)

    第12章 输入与输出 Qt提供了读写字节块的设备类QIODevice QIODevice类是抽象的 无法被实例化 一般是使用它的子类 它包括如下子类 其中 QProcess QTcpSocket QUdpSocket QSslSocket都
  • Java 优先级队列

    文章目录 Java 优先级队列 PriorityQueue简介 继承关系 PriorityQueue示例 Comparable比较器 Comparable接口 Comparator比较器 Comparator接口 底层原理 Java 优先级
  • Unity3d 游戏优化 mono等

    GC问题 1 C 变量分为两种类型 值类型和引用类型 值类型分配在栈区 引用类型分配在堆区 GC关注引用类型 2 GC卡顿原因 堆内存垃圾回收 向系统申请新的堆内存 3 GC触发条件 堆内存分配而当内存不足时 按频率自动触发 手动强行触发
  • 【Vue】 前端上传图片时限制只可以按文件夹上传图片( webkitdirectory )

    前言 最近再对公司前后端不分离的 C Winform 系统进行 Java Web 重构 为了保持客户使用习惯所以要高度还原 其中有一个功能就是上传图片时 以文件夹进行上传 要读取文件夹内所有的图片 看了挺多大神的博客 也看了 Element
  • Keepalived与HaProxy的协调合作原理分析

    Keepalived与HaProxy的协调合作原理分析 keepalived与haproxy合作场景 更好的理解方式 协调合作中考虑的问题 一 Keepalived 以TCP IP模型角度来分析 二 HaProxy 总结 协调合作中考虑的问
  • Go-Python-Java-C-LeetCode高分解法-第四周合集

    前言 本题解Go语言部分基于 LeetCode Go 其他部分基于本人实践学习 个人题解GitHub连接 LeetCode Go Python Java C Go Python Java C LeetCode高分解法 第一周合集 Go Py
  • 由于找不到d3dx9_43.dll无法继续执行-修复教程

    d3dx9 43 dll是一个非常重要的DLL文件 它属于微软DirectX 9 0c的一部分 它主要用于游戏应用程序的开发和运行 在使用Windows平台的玩家中非常常见 这个文件通过DirectX接口提供了一些相关的功能 比如图像和声音
  • 该服务器因不稳定无法正常反应,服务器连接异常

    服务器连接异常 内容精选 换一换 ELB的常见异常返回码有400 403 502 504等 若遇到这些返回码建议您先直接访问后端云服务器 查看是否是后端云服务器的异常 若后端云服务器响应正常 请参考表1排查处理 如果仍无法解决 请联系客服人
  • 非关系型数据库、关系型数据库mysql简介

    Nosql 非关系数据库 数据存储不需要固定的模式 NoSql特点 易扩展 数据之间无关系 大数据量高性能 细粒度 cache性能高 多样灵活的数据模型 增删字段容易 关系数据库 vs NoSql 传统关系数据库 ACID 事务所具有的四个
  • 【华为OD机试】组成最大数 (C++ Python Java)2023 B卷

    题目描述 小组中每位都有一张卡片 卡片上是6位内的正整数 将卡片连起来可以组成多种数字 计算组成的最大数字 输入描述 号分割的多个正整数字符串 不需要考虑非数字异常情况 小组最多25个人 输出描述 最大的数字字符串 用例1 输入 22 22
  • 机械电子工程用不用学c语言,机械电子工程到底学什么 毕业以后能干什么

    机械电子工程专业俗称机电一体化 是机械工程与自动化的一种 下文有途网小编给大家整理了机械电子工程的就业方向及前景 供参考 机械电子工程专业主要学什么 机械电子工程要学习得课程有 电工与电子技术 机械制图 工程力学 机械设计基础 机械制造基础
  • 红队打靶,红日系列,红日靶场5

    文章目录 靶场详情 外网渗透 端口扫描 漏洞发现与利用 获取shell 内网渗透 提权 内网信息收集 横向移动 第一种使用CS 第二种使用msf 路由转发与代理通道 Psexec 攻击 靶场详情 此次靶场虚拟机共用两个 一个外网一个内网 用
  • java实现二分查找-两种方式

    二分查找是一种查询效率非常高的查找算法 又称折半查找 起初在数据结构中学习递归时实现二分查找 实际上不用递归也可以实现 毕竟递归是需要开辟额外的空间的来辅助查询 本文就介绍两种方法 二分查找算法思想 有序的序列 每次都是以序列的中间位置的数
  • 看融合数学教学的steam教育模式

    传统意义上的 教育 德育 教学双肩挑 是要求教师能够处理好 德育 和 教学 两方面的工作要求 这实质上是通过人为划分的两个途径实现对学生的培养 STEAM教育的跨学科整合思维能够很好的迁移在 德育 与 教学 的整合上 即在教师引导下的学生参
  • OWASP Top 10 2021 榜单出炉,安全人员必看

    作为一个安全人员 如果你还不知道OWASP Top 10是什么 那么请你接着往下看 OWASP 开放式Web应用程序安全项目 是一个开源的 非营利性的全球性安全组织 致力于改进Web应用程序的安全 这个组织最出名是 它总结了10种最严重的W
  • 数据结构小白之队列与环形队列的模拟

    队列的简单介绍 队列是一个有序列表 可以使用数组或者链表来实现 队列遵循先入先出的原则 先存入队列的数据要先取出 后存入的后取出 使用数组来模拟队列 说明 实现思路 示意图 代码 1 说明 队列本身是有序列表 若使用数组的结构来存储队列的数
  • 安装和更新node的正确姿势

    干货时刻 本文主要讲解了如何安装node 以及如何更新node的版本 node js 是什么 简称node 是基于Chrome V8引擎的JavaScript JS 运行时环境 node 安装 进入node 官网 点击如下图所示的安装包即可
  • 前端之HTML

    一 概念 1 页面组成 结构 HTML Hyper Text Markup Language 超文本标记语言 页面原始和内容 表现 CSS 网页原始的外观和位置等页面样式 如颜色 大小等 行为 JavaScript 网页模型的定义与交互 简
  • 计算机组成原理慕课测试-第四单元

    计算机字长32位 主存容量为128MB 按字编址 其寻址范围为 0 32M 1 1 B 8b 1 kB 1024 B kB kilobajt 千 1 MB 1024 kB MB megabajt 兆 1 MB 1024 kB MB mega
  • IPV6 阿里DDNS

    IPV6 阿里DDNS 因为需要在家搭建一套环境 并且需要公网能访问 国内的ipv4的地址 各大运营商基本都不会分配ipv4地址 电信宽带好像有地方可以 但是听说很贵 而且是动态的 每过段时间就会改变 发现移动宽带的公网ipv6地址是可以获