`

java读取QQwry.dat获得ip地址对应实际位置

    博客分类:
  • java
阅读更多

 

之前找的IP库读取工具类

IPEntry.java

package test.ip;
/**
 * <pre>
 * 一条IP范围记录,不仅包括国家和区域,也包括起始IP和结束IP
 * </pre>
 */
public class IPEntry {

    public String beginIp;
    public String endIp;
    public String country;
    public String area;

    /**
     * 构造函数
     */
    public IPEntry() {
        beginIp = endIp = country = area = "";
    }
}

IPLocation.java

package test.ip;

/**
 *
 * @category 用来封装ip相关信息,目前只有两个字段,ip所在的国家和地区
 */
public class IPLocation {

    private String country;
    private String area;

    public IPLocation() {
        country = area = "";
    }

    public IPLocation getCopy() {
        IPLocation ret = new IPLocation();
        ret.country = country;
        ret.area = area;
        return ret;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getArea() {
        return area;
    }

    public void setArea(String area) {
        //如果为局域网,纯真IP地址库的地区会显示CZ88.NET,这里把它去掉
        if (area.trim().equals("CZ88.NET")) {
            this.area = "本机或本网络";
        } else {
            this.area = area;
        }
    }
}

IPSeeker.java 

package test.ip;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Level;

public class IPSeeker {
    //纯真IP数据库名

    private String IP_FILE;
    private static String DEFAULT_IP_FILE = "QQWry.Dat";
    //保存的文件夹
    private String INSTALL_DIR;
    private static String DEFAULT_INSTALL_DIR = IPSeeker.class.getResource("/../../WEB-INF/ip").getPath();
    // 一些固定常量,比如记录长度等等
    private static final int IP_RECORD_LENGTH = 7;
    private static final byte REDIRECT_MODE_1 = 0x01;
    private static final byte REDIRECT_MODE_2 = 0x02;

    // 用来做为cache,查询一个ip时首先查看cache,以减少不必要的重复查找
    private Map<String, IPLocation> ipCache;
    // 随机文件访问类
    private RandomAccessFile ipFile;
    // 内存映射文件
    private MappedByteBuffer mbb;
    // 起始地区的开始和结束的绝对偏移
    private long ipBegin,  ipEnd;
    // 为提高效率而采用的临时变量
    private IPLocation loc;
    private byte[] buf;
    private byte[] b4;
    private byte[] b3;
    private static IPSeeker seek = new IPSeeker(DEFAULT_IP_FILE, DEFAULT_INSTALL_DIR);

    public static IPSeeker getInstance() {
        return seek;
    }

    private IPSeeker(String fileName, String dir) {
        this.INSTALL_DIR = dir;
        this.IP_FILE = fileName;
        ipCache = new HashMap<String, IPLocation>();
        loc = new IPLocation();
        buf = new byte[65536];
        b4 = new byte[4];
        b3 = new byte[3];
        try {
            ipFile = new RandomAccessFile(IP_FILE, "r");
        } catch (FileNotFoundException e) {
            // 如果找不到这个文件,再尝试再当前目录下搜索,这次全部改用小写文件名
            //     因为有些系统可能区分大小写导致找不到ip地址信息文件
            String filename = new File(IP_FILE).getName().toLowerCase();
            File[] files = new File(INSTALL_DIR).listFiles();
            for (int i = 0; i < files.length; i++) {
                if (files[i].isFile()) {
                    if (files[i].getName().toLowerCase().equals(filename)) {
                        try {
                            ipFile = new RandomAccessFile(files[i], "r");
                        } catch (FileNotFoundException e1) {
                            LogFactory.log("IP地址信息文件没有找到,IP显示功能将无法使用", Level.ERROR, e1);
                            ipFile = null;
                        }
                        break;
                    }
                }
            }
        }
        // 如果打开文件成功,读取文件头信息
        if (ipFile != null) {
            try {
                ipBegin = readLong4(0);
                ipEnd = readLong4(4);
                if (ipBegin == -1 || ipEnd == -1) {
                    ipFile.close();
                    ipFile = null;
                }
            } catch (IOException e) {
                LogFactory.log("IP地址信息文件格式有错误,IP显示功能将无法使用", Level.ERROR, e);
                ipFile = null;
            }
        }
    }

    /**
     * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
     * @param s 地点子串
     * @return 包含IPEntry类型的List
     */
    public List<IPEntry> getIPEntriesDebug(String s) {
        List<IPEntry> ret = new ArrayList<IPEntry>();
        long endOffset = ipEnd + 4;
        for (long offset = ipBegin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
            // 读取结束IP偏移
            long temp = readLong3(offset);
            // 如果temp不等于-1,读取IP的地点信息
            if (temp != -1) {
                IPLocation ipLoc = getIPLocation(temp);
                // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续
                if (ipLoc.getCountry().indexOf(s) != -1 || ipLoc.getArea().indexOf(s) != -1) {
                    IPEntry entry = new IPEntry();
                    entry.country = ipLoc.getCountry();
                    entry.area = ipLoc.getArea();
                    // 得到起始IP
                    readIP(offset - 4, b4);
                    entry.beginIp = Util.getIpStringFromBytes(b4);
                    // 得到结束IP
                    readIP(temp, b4);
                    entry.endIp = Util.getIpStringFromBytes(b4);
                    // 添加该记录
                    ret.add(entry);
                }
            }
        }
        return ret;
    }

    public IPLocation getIPLocation(String ip) {
        IPLocation location = new IPLocation();
        location.setArea(this.getArea(ip));
        location.setCountry(this.getCountry(ip));
        return location;
    }

    /**
     * 给定一个地点的不完全名字,得到一系列包含s子串的IP范围记录
     * @param s 地点子串
     * @return 包含IPEntry类型的List
     */
    public List<IPEntry> getIPEntries(String s) {
        List<IPEntry> ret = new ArrayList<IPEntry>();
        try {
            // 映射IP信息文件到内存中
            if (mbb == null) {
                FileChannel fc = ipFile.getChannel();
                mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, ipFile.length());
                mbb.order(ByteOrder.LITTLE_ENDIAN);
            }

            int endOffset = (int) ipEnd;
            for (int offset = (int) ipBegin + 4; offset <= endOffset; offset += IP_RECORD_LENGTH) {
                int temp = readInt3(offset);
                if (temp != -1) {
                    IPLocation ipLoc = getIPLocation(temp);
                    // 判断是否这个地点里面包含了s子串,如果包含了,添加这个记录到List中,如果没有,继续
                    if (ipLoc.getCountry().indexOf(s) != -1 || ipLoc.getArea().indexOf(s) != -1) {
                        IPEntry entry = new IPEntry();
                        entry.country = ipLoc.getCountry();
                        entry.area = ipLoc.getArea();
                        // 得到起始IP
                        readIP(offset - 4, b4);
                        entry.beginIp = Util.getIpStringFromBytes(b4);
                        // 得到结束IP
                        readIP(temp, b4);
                        entry.endIp = Util.getIpStringFromBytes(b4);
                        // 添加该记录
                        ret.add(entry);
                    }
                }
            }
        } catch (IOException e) {
            LogFactory.log("", Level.ERROR, e);
        }
        return ret;
    }

    /**
     * 从内存映射文件的offset位置开始的3个字节读取一个int
     * @param offset
     * @return
     */
    private int readInt3(int offset) {
        mbb.position(offset);
        return mbb.getInt() & 0x00FFFFFF;
    }

    /**
     * 从内存映射文件的当前位置开始的3个字节读取一个int
     * @return
     */
    private int readInt3() {
        return mbb.getInt() & 0x00FFFFFF;
    }

    /**
     * 根据IP得到国家名
     * @param ip ip的字节数组形式
     * @return 国家名字符串
     */
    public String getCountry(byte[] ip) {
        // 检查ip地址文件是否正常
        if (ipFile == null) {
            return Message.bad_ip_file;
        }
        // 保存ip,转换ip字节数组为字符串形式
        String ipStr = Util.getIpStringFromBytes(ip);
        // 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
        if (ipCache.containsKey(ipStr)) {
            IPLocation ipLoc = ipCache.get(ipStr);
            return ipLoc.getCountry();
        } else {
            IPLocation ipLoc = getIPLocation(ip);
            ipCache.put(ipStr, ipLoc.getCopy());
            return ipLoc.getCountry();
        }
    }

    /**
     * 根据IP得到国家名
     * @param ip IP的字符串形式
     * @return 国家名字符串
     */
    public String getCountry(String ip) {
        return getCountry(Util.getIpByteArrayFromString(ip));
    }

    /**
     * 根据IP得到地区名
     * @param ip ip的字节数组形式
     * @return 地区名字符串
     */
    public String getArea(byte[] ip) {
        // 检查ip地址文件是否正常
        if (ipFile == null) {
            return Message.bad_ip_file;
        }
        // 保存ip,转换ip字节数组为字符串形式
        String ipStr = Util.getIpStringFromBytes(ip);
        // 先检查cache中是否已经包含有这个ip的结果,没有再搜索文件
        if (ipCache.containsKey(ipStr)) {
            IPLocation ipLoc = ipCache.get(ipStr);
            return ipLoc.getArea();
        } else {
            IPLocation ipLoc = getIPLocation(ip);
            ipCache.put(ipStr, ipLoc.getCopy());
            return ipLoc.getArea();
        }
    }

    /**
     * 根据IP得到地区名
     * @param ip IP的字符串形式
     * @return 地区名字符串
     */
    public String getArea(String ip) {
        return getArea(Util.getIpByteArrayFromString(ip));
    }

    /**
     * 根据ip搜索ip信息文件,得到IPLocation结构,所搜索的ip参数从类成员ip中得到
     * @param ip 要查询的IP
     * @return IPLocation结构
     */
    public IPLocation getIPLocation(byte[] ip) {
        IPLocation info = null;
        long offset = locateIP(ip);
        if (offset != -1) {
            info = getIPLocation(offset);
        }
        if (info == null) {
            info = new IPLocation();
            info.setCountry(Message.unknown_country);
            info.setArea(Message.unknown_area);
        }
        return info;
    }

    /**
     * 从offset位置读取4个字节为一个long,因为java为big-endian格式,所以没办法
     * 用了这么一个函数来做转换
     * @param offset
     * @return 读取的long值,返回-1表示读取文件失败
     */
    private long readLong4(long offset) {
        long ret = 0;
        try {
            ipFile.seek(offset);
            ret |= (ipFile.readByte() & 0xFF);
            ret |= ((ipFile.readByte() << 8) & 0xFF00);
            ret |= ((ipFile.readByte() << 16) & 0xFF0000);
            ret |= ((ipFile.readByte() << 24) & 0xFF000000);
            return ret;
        } catch (IOException e) {
            return -1;
        }
    }

    /**
     * 从offset位置读取3个字节为一个long,因为java为big-endian格式,所以没办法
     * 用了这么一个函数来做转换
     * @param offset 整数的起始偏移
     * @return 读取的long值,返回-1表示读取文件失败
     */
    private long readLong3(long offset) {
        long ret = 0;
        try {
            ipFile.seek(offset);
            ipFile.readFully(b3);
            ret |= (b3[0] & 0xFF);
            ret |= ((b3[1] << 8) & 0xFF00);
            ret |= ((b3[2] << 16) & 0xFF0000);
            return ret;
        } catch (IOException e) {
            return -1;
        }
    }

    /**
     * 从当前位置读取3个字节转换成long
     * @return 读取的long值,返回-1表示读取文件失败
     */
    private long readLong3() {
        long ret = 0;
        try {
            ipFile.readFully(b3);
            ret |= (b3[0] & 0xFF);
            ret |= ((b3[1] << 8) & 0xFF00);
            ret |= ((b3[2] << 16) & 0xFF0000);
            return ret;
        } catch (IOException e) {
            return -1;
        }
    }

    /**
     * 从offset位置读取四个字节的ip地址放入ip数组中,读取后的ip为big-endian格式,但是
     * 文件中是little-endian形式,将会进行转换
     * @param offset
     * @param ip
     */
    private void readIP(long offset, byte[] ip) {
        try {
            ipFile.seek(offset);
            ipFile.readFully(ip);
            byte temp = ip[0];
            ip[0] = ip[3];
            ip[3] = temp;
            temp = ip[1];
            ip[1] = ip[2];
            ip[2] = temp;
        } catch (IOException e) {
            LogFactory.log("", Level.ERROR, e);
        }
    }

    /**
     * 从offset位置读取四个字节的ip地址放入ip数组中,读取后的ip为big-endian格式,但是
     * 文件中是little-endian形式,将会进行转换
     * @param offset
     * @param ip
     */
    private void readIP(int offset, byte[] ip) {
        mbb.position(offset);
        mbb.get(ip);
        byte temp = ip[0];
        ip[0] = ip[3];
        ip[3] = temp;
        temp = ip[1];
        ip[1] = ip[2];
        ip[2] = temp;
    }

    /**
     * 把类成员ip和beginIp比较,注意这个beginIp是big-endian的
     * @param ip 要查询的IP
     * @param beginIp 和被查询IP相比较的IP
     * @return 相等返回0,ip大于beginIp则返回1,小于返回-1。
     */
    private int compareIP(byte[] ip, byte[] beginIp) {
        for (int i = 0; i < 4; i++) {
            int r = compareByte(ip[i], beginIp[i]);
            if (r != 0) {
                return r;
            }
        }
        return 0;
    }

    /**
     * 把两个byte当作无符号数进行比较
     * @param b1
     * @param b2
     * @return 若b1大于b2则返回1,相等返回0,小于返回-1
     */
    private int compareByte(byte b1, byte b2) {
        if ((b1 & 0xFF) > (b2 & 0xFF)) // 比较是否大于
        {
            return 1;
        } else if ((b1 ^ b2) == 0)// 判断是否相等
        {
            return 0;
        } else {
            return -1;
        }
    }

    /**
     * 这个方法将根据ip的内容,定位到包含这个ip国家地区的记录处,返回一个绝对偏移
     * 方法使用二分法查找。
     * @param ip 要查询的IP
     * @return 如果找到了,返回结束IP的偏移,如果没有找到,返回-1
     */
    private long locateIP(byte[] ip) {
        long m = 0;
        int r;
        // 比较第一个ip项
        readIP(ipBegin, b4);
        r = compareIP(ip, b4);
        if (r == 0) {
            return ipBegin;
        } else if (r < 0) {
            return -1;
        }
        // 开始二分搜索
        for (long i = ipBegin, j = ipEnd; i < j;) {
            m = getMiddleOffset(i, j);
            readIP(m, b4);
            r = compareIP(ip, b4);
            // log.debug(Utils.getIpStringFromBytes(b));
            if (r > 0) {
                i = m;
            } else if (r < 0) {
                if (m == j) {
                    j -= IP_RECORD_LENGTH;
                    m = j;
                } else {
                    j = m;
                }
            } else {
                return readLong3(m + 4);
            }
        }
        // 如果循环结束了,那么i和j必定是相等的,这个记录为最可能的记录,但是并非
        //     肯定就是,还要检查一下,如果是,就返回结束地址区的绝对偏移
        m = readLong3(m + 4);
        readIP(m, b4);
        r = compareIP(ip, b4);
        if (r <= 0) {
            return m;
        } else {
            return -1;
        }
    }

    /**
     * 得到begin偏移和end偏移中间位置记录的偏移
     * @param begin
     * @param end
     * @return
     */
    private long getMiddleOffset(long begin, long end) {
        long records = (end - begin) / IP_RECORD_LENGTH;
        records >>= 1;
        if (records == 0) {
            records = 1;
        }
        return begin + records * IP_RECORD_LENGTH;
    }

    /**
     * 给定一个ip国家地区记录的偏移,返回一个IPLocation结构
     * @param offset 国家记录的起始偏移
     * @return IPLocation对象
     */
    private IPLocation getIPLocation(long offset) {
        try {
            // 跳过4字节ip
            ipFile.seek(offset + 4);
            // 读取第一个字节判断是否标志字节
            byte b = ipFile.readByte();
            if (b == REDIRECT_MODE_1) {
                // 读取国家偏移
                long countryOffset = readLong3();
                // 跳转至偏移处
                ipFile.seek(countryOffset);
                // 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向
                b = ipFile.readByte();
                if (b == REDIRECT_MODE_2) {
                    loc.setCountry(readString(readLong3()));
                    ipFile.seek(countryOffset + 4);
                } else {
                    loc.setCountry(readString(countryOffset));
                }
                // 读取地区标志
                loc.setArea(readArea(ipFile.getFilePointer()));
            } else if (b == REDIRECT_MODE_2) {
                loc.setCountry(readString(readLong3()));
                loc.setArea(readArea(offset + 8));
            } else {
                loc.setCountry(readString(ipFile.getFilePointer() - 1));
                loc.setArea(readArea(ipFile.getFilePointer()));
            }
            return loc;
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 给定一个ip国家地区记录的偏移,返回一个IPLocation结构,此方法应用与内存映射文件方式
     * @param offset 国家记录的起始偏移
     * @return IPLocation对象
     */
    private IPLocation getIPLocation(int offset) {
        // 跳过4字节ip
        mbb.position(offset + 4);
        // 读取第一个字节判断是否标志字节
        byte b = mbb.get();
        if (b == REDIRECT_MODE_1) {
            // 读取国家偏移
            int countryOffset = readInt3();
            // 跳转至偏移处
            mbb.position(countryOffset);
            // 再检查一次标志字节,因为这个时候这个地方仍然可能是个重定向
            b = mbb.get();
            if (b == REDIRECT_MODE_2) {
                loc.setCountry(readString(readInt3()));
                mbb.position(countryOffset + 4);
            } else {
                loc.setCountry(readString(countryOffset));
            }
            // 读取地区标志
            loc.setArea(readArea(mbb.position()));
        } else if (b == REDIRECT_MODE_2) {
            loc.setCountry(readString(readInt3()));
            loc.setArea(readArea(offset + 8));
        } else {
            loc.setCountry(readString(mbb.position() - 1));
            loc.setArea(readArea(mbb.position()));
        }
        return loc;
    }

    /**
     * 从offset偏移开始解析后面的字节,读出一个地区名
     * @param offset 地区记录的起始偏移
     * @return 地区名字符串
     * @throws IOException
     */
    private String readArea(long offset) throws IOException {
        ipFile.seek(offset);
        byte b = ipFile.readByte();
        if (b == REDIRECT_MODE_1 || b == REDIRECT_MODE_2) {
            long areaOffset = readLong3(offset + 1);
            if (areaOffset == 0) {
                return Message.unknown_area;
            } else {
                return readString(areaOffset);
            }
        } else {
            return readString(offset);
        }
    }

    /**
     * @param offset 地区记录的起始偏移
     * @return 地区名字符串
     */
    private String readArea(int offset) {
        mbb.position(offset);
        byte b = mbb.get();
        if (b == REDIRECT_MODE_1 || b == REDIRECT_MODE_2) {
            int areaOffset = readInt3();
            if (areaOffset == 0) {
                return Message.unknown_area;
            } else {
                return readString(areaOffset);
            }
        } else {
            return readString(offset);
        }
    }

    /**
     * 从offset偏移处读取一个以0结束的字符串
     * @param offset 字符串起始偏移
     * @return 读取的字符串,出错返回空字符串
     */
    private String readString(long offset) {
        try {
            ipFile.seek(offset);
            int i;
            for (i = 0, buf[i] = ipFile.readByte(); buf[i] != 0; buf[++i] = ipFile.readByte());
            if (i != 0) {
                return Util.getString(buf, 0, i, "GBK");
            }
        } catch (IOException e) {
            LogFactory.log("", Level.ERROR, e);
        }
        return "";
    }

    /**
     * 从内存映射文件的offset位置得到一个0结尾字符串
     * @param offset 字符串起始偏移
     * @return 读取的字符串,出错返回空字符串
     */
    private String readString(int offset) {
        try {
            mbb.position(offset);
            int i;
            for (i = 0, buf[i] = mbb.get(); buf[i] != 0; buf[++i] = mbb.get());
            if (i != 0) {
                return Util.getString(buf, 0, i, "GBK");
            }
        } catch (IllegalArgumentException e) {
            LogFactory.log("", Level.ERROR, e);
        }
        return "";
    }
}
分享到:
评论

相关推荐

    太阳能自动灌溉系统:基于SPWM技术的逆变正弦波设计与实现

    内容概要:本文详细介绍了太阳能自动灌溉系统的设计与实现,涵盖了多个关键技术点。首先,文章解释了太阳能自动灌溉系统的概念及其优势,如高效节水、环保等。接着,深入探讨了SPWM(正弦脉宽调制)技术,展示了如何通过调节脉冲宽度将直流电转换为正弦波形的交流电,这是逆变器工作的核心技术。随后,讨论了仿真的重要性,特别是使用MATLAB/Simulink进行系统行为和性能的模拟,确保设计方案的可行性。此外,还涉及了编程方面,通过Python和C语言实现了系统的控制逻辑,如根据土壤湿度控制灌溉。最后,介绍了DXP原理图在电路设计中的应用,强调了合理的电路布局和防护措施对于系统稳定性的关键作用。 适合人群:对太阳能技术和自动化控制系统感兴趣的工程师和技术爱好者,尤其是有一定电子电路和编程基础的人群。 使用场景及目标:适用于希望深入了解太阳能自动灌溉系统设计和实现的个人或团队,目标是掌握从能源获取、电力转换、系统模拟到代码控制以及电路设计的全流程,最终能够独立构建高效的太阳能自动灌溉系统。 其他说明:文中提供了大量实例代码和实践经验,帮助读者更好地理解和应用相关技术。同时,强调了实际操作中的注意事项,如

    (源码)基于Vue.js的通用组件库.zip

    # 基于Vue.js的通用组件库 ## 项目简介 此项目是基于Vue.js构建的组件库,涵盖了Button、Form、FormItem、Input、Notice等多个可复用组件。它具备组件测试、文档生成、自定义主题、按需加载、组件数据通信等功能,并且通过Webpack完成打包,方便在各类Vue项目中使用。 ## 项目的主要特性和功能 1. 多种加载方式支持全局引入和按需加载,可根据项目需求灵活选择。 2. 文档生成利用VuePress工具生成组件文档,便于用户查看组件使用方法和样式。 3. 自定义主题能通过修改样式变量来自定义组件主题,满足不同项目的个性化需求。 4. 组件数据通信通过dispatch和broadcast方法实现组件间的数据通信,提升组件库的扩展性。 5. 独立打包样式文件和组件文件分别打包,可单独加载,减少代码量和加载时间。 ## 安装使用步骤 ### 准备工作 确保已经安装基本的Node.js和npm环境,以及Git。

    (源码)基于Python的机器学习基础项目.zip

    # 基于Python的机器学习基础项目 ## 项目简介 本项目是一个基于Python的机器学习基础项目,涵盖了线性回归、逻辑回归、感知器算法(PLA)及其改进版(Pocket PLA)等机器学习算法的实现。项目通过不同算法处理不同数据集,并展示了这些算法在分类和回归问题上的应用。 ## 项目的主要特性和功能 线性回归实现了基于梯度下降法的线性回归算法,用于拟合数据并预测目标值。 逻辑回归提供了使用梯度下降法和随机梯度下降法的逻辑回归实现,用于分类任务。 感知器算法实现了基本的感知器学习算法(PLA)和Pocket PLA算法,用于线性分类问题。 数据加载与预处理提供了数据加载和预处理功能,支持不同格式的数据输入。 误差计算与性能评估提供了计算模型误差(误差率或准确率)的功能,用于评估模型性能。 ## 安装使用步骤 1. 环境准备确保已安装Python及其相关库(如NumPy、SciPy等)。

    幼儿园教师师德培训教学课件.pptx

    幼儿园教师师德培训教学课件

    JavaWeb电商系统开发基础教程

    JavaWeb技术在当今的互联网开发中占据着重要的地位,尤其是在电商系统开发领域。通过JavaWeb,我们可以构建出功能强大、稳定可靠的电商网站。本教程将带你从零开始,逐步掌握JavaWeb电商系统开发的基础知识和技能。

    LabVIEW开发的三支路测试设备软件与PLC程序:状态机架构与ModBUS通信设计

    内容概要:本文详细介绍了作者使用LabVIEW开发一台三支路并行测试设备的上位机软件及其PLC程序的经验。项目涉及多个关键技术点,如LabVIEW的图形化编程特性、状态机设计模式的应用、ModBUS TCP/IP通信协议的实现等。文中不仅解释了LabVIEW的基本操作和代码结构,还深入探讨了如何通过单状态机引擎和支路编号分流实现多支路独立控制的方法。此外,作者分享了一些实用的通信异常处理技巧和优化策略,如心跳包机制、数据采集与逻辑处理的交错执行等。 适合人群:具有一定LabVIEW基础的学习者和工程师,尤其是从事自动化测试设备开发的技术人员。 使用场景及目标:适用于需要开发复杂测试系统的工程师,帮助他们掌握如何在单线程环境中实现多支路独立控制,提高系统的稳定性和效率。目标是提供一种高效、可靠的开发思路和技术实现方法。 其他说明:文中提到的具体技术和实践经验对于中小型测试系统的开发具有较高的参考价值,特别是状态机设计和ModBUS通信部分的内容。

    #_ssm_134_mysql_新冠疫苗接种管理系统_.zip

    Java项目t基于ssm的课程设计,包含源码+数据库+论文

    Object Oriented Programming Using C++

    Object Oriented Programming Using C++

    (源码)基于C++的CWMP客户端实现.zip

    # 基于C++的CWMP客户端实现 ## 项目简介 本项目是一个基于C++实现的CWMP(Connected Without Plugging Management)客户端,用于与DSL(数字用户线)设备进行配置管理交互。它实现了TR069 1.2版本的客户端程序,支持基本的RPC方法和TR181数据模型,并实现了系统升级、恢复出厂、重启等功能。 ## 主要特性和功能 实现了TR069 1.2版本的客户端程序,支持基本的RPC方法和TR181数据模型。 提供了系统升级、恢复出厂、重启等功能,并只支持安卓平台。 支持Linux和Windows操作系统,并提供了相应的处理逻辑。 使用第三方库如curl和tinyxml2来处理网络请求和XML解析。 提供了命令行参数处理功能,支持启动时上报事件、获取RPC方法等。 支持从备份文件中加载配置信息,包括上传、下载和事件等。 实现了事件处理逻辑,包括定时通知和响应处理。 ## 安装使用步骤

    计算机网络实验4:拥塞控制算法(Reno与BBR)的实现与对比分析

    内容概要:本文档是一份关于网络拥塞控制算法的大学实验报告,重点介绍了TCP-Reno和TCP-BBR两种拥塞控制算法的实现及其性能对比。实验分为三部分:首先是观察拥塞现象,通过改变路由器队列长度和链路带宽,研究其对丢包率和有效吞吐量的影响;其次是实现TCP-Reno算法,详细解析了其慢启动、拥塞避免、快速重传和快速恢复四个阶段的工作机制;最后是实现TCP-BBR算法,探讨了其基于带宽和延迟测量的拥塞控制机制,包括带宽估计、RTT估计、发送速率控制和拥塞窗口调整。实验结果显示,TCP-BBR在低延迟高带宽环境中表现出色,而TCP-Reno更适合高延迟低带宽环境。 适合人群:具备一定网络基础知识的学生、研究人员和技术人员。 使用场景及目标:①理解网络拥塞现象及其对数据传输的影响;②掌握TCP-Reno和TCP-BBR两种拥塞控制算法的具体实现;③通过实验数据分析,比较两种算法在不同网络条件下的优劣。 其他说明:实验使用OMNet++模拟器和INET框架进行仿真测试,提供了详细的代码片段和实验结果图表,便于理解和复现。

    (源码)基于Arduino的MIDI控制器项目.zip

    # 基于Arduino的MIDI控制器项目 ## 项目简介 此项目旨在利用旧式模拟音频设备上的对数滑动电位计制作一个MIDI控制器。通过使用Arduino Pro Micro和74HC4051模拟多路复用器,实现对MIDI信号的接收与传输。项目作者Evan Kale提供了详细的构建指南和演示视频,以帮助爱好者们完成自己的MIDI控制器制作。 ## 项目的主要特性和功能 利用废旧模拟音频设备的电位计作为输入设备。 使用Arduino Pro Micro作为核心控制器,实现对MIDI信号的接收与传输。 利用74HC4051模拟多路复用器增加额外的输入。 兼容Ralf Kistner的arcore补丁,为Arduino IDE环境添加MIDIUSB支持。 ## 安装使用步骤 1. 下载源码文件请确保您已经下载了此项目的源代码文件,其中包括Arduino的编程代码和相关文件。

    (源码)基于STM32的电力电子设备远程监控系统.zip

    # 基于STM32的电力电子设备远程监控系统 ## 项目简介 本项目是一个基于STM32F407ZGT6微控制器的电力电子设备远程监控系统。系统通过STM32F407ZGT6核心板实现了电路的三相电压电流采样、信号调理、AD转换、以太网通信及PC端可视化监测功能。项目旨在通过嵌入式系统设计,实现对电力电子设备运行状态的实时远程监控。 ## 主要功能和技术 1. 信号采样与调理通过Altium Designer设计的硬件电路,实现了三相电压和电流的采样与信号调理。 2. AD转换使用STM32F407ZGT6的ADC模块,实现了多通道电压和电流信号的AD转换,并通过DMA进行数据传输。 3. 以太网通信基于LWIP协议栈,实现了UDP通信功能,支持远程数据传输与监控。 4. PC端监控界面使用LabVIEW 2018开发了PC端监控界面,能够实时显示电力电子设备的运行状态。 ## 安装与使用步骤 1. 硬件准备

    transmission-gtk-3.00-1.el8.x64-86.rpm.tar.gz

    1、文件说明: Centos8操作系统transmission-gtk-3.00-1.el8.rpm以及相关依赖,全打包为一个tar.gz压缩包 2、安装指令: #Step1、解压 tar -zxvf transmission-gtk-3.00-1.el8.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm

    台达DOP触摸屏与VFD-S1变频器MODBUS RTU通信实现及应用场景

    内容概要:本文详细介绍了台达DOP触摸屏与VFD-S1变频器通过MODBUS RTU协议实现直接通信的方法。首先解释了自动化控制的重要性和各组件的作用,接着逐步讲解了硬件连接、通信参数设置、控制逻辑编程(如启动、停止、正反转、频率设定)以及实时监控功能的具体实现方法。文中还分享了一些实用的设计技巧和常见问题解决办法,确保通信稳定可靠。最后强调了这种直接通信方式的优势及其广泛的应用前景。 适合人群:从事自动化控制领域的工程师和技术人员,尤其是那些希望深入了解触摸屏与变频器直接通信机制的专业人士。 使用场景及目标:适用于需要优化生产设备控制的小型工厂或企业,旨在减少中间环节降低成本的同时提升系统的响应速度和稳定性。通过学习本文提供的实例,读者可以掌握如何快速搭建并调试类似的自动化控制系统。 其他说明:文中提到的技术细节对于理解和实施此类项目非常有价值,同时也提醒读者在实际操作过程中应注意的安全事项和潜在风险。

    (源码)基于Arduino的硬件随机数生成器.zip

    # 基于Arduino的硬件随机数生成器 ## 项目简介 本项目提供了一个基于Arduino的硬件随机数生成器,旨在通过物理事件生成高质量的随机数。项目使用NE555自由运行振荡器,并通过其时钟漂移作为随机性的来源。生成的随机数可以用于多种应用,包括密码学和模拟实验。 ## 项目的主要特性和功能 硬件随机数生成使用NE555振荡器的时钟漂移作为随机性来源。 可配置固件通过内置命令行界面配置随机数生成器的参数。 多种随机数处理方法支持批量采样、掩码、移位、延迟等多种处理方法。 统计测试工具提供ent、rngtest和dieharder等工具,用于测试生成的随机数序列的质量。 USB接口通过USB接口将生成的随机数反馈到Linux系统的熵池中。 ## 安装使用步骤 ### 1. 硬件准备 按照Eagle PCB设计文件准备硬件组件。 将硬件组件焊接在PCB板上,并确保所有连接正确。 ### 2. 固件烧录

    LabVIEW与Halcon联合编程:图像处理与自动化控制的高效集成

    内容概要:本文详细介绍了LabVIEW与Halcon联合编程的具体实现方法及其应用场景。主要内容涵盖三个关键步骤:LabVIEW采集图像、将图像传递给Halcon处理以及LabVIEW读取并展示Halcon的处理结果。文中还深入讨论了图像数据传递的最佳实践,如直接内存传递而非保存再读取的方式,提高了效率。此外,文章提供了使用.NET构造器调用Halcon算子和HDevEngine调用Halcon脚本的方法,并分享了多个实用技巧,如内存管理、版本兼容性和性能优化等。 适合人群:从事图像处理、自动化控制领域的工程师和技术人员,尤其是对LabVIEW和Halcon有一定了解的开发者。 使用场景及目标:适用于需要高效图像处理和自动化控制的工业检测项目,旨在提高图像处理的速度和准确性,减少开发时间和成本。 其他说明:文中提到的技术细节和代码示例均基于LabVIEW 2018 (32-bit) 和 Halcon 17,对于更高版本或其他环境可能需要调整。同时,作者强调了版本兼容性和内存管理的重要性,提醒读者在实际应用中要注意这些问题。

    (源码)基于Arduino的CNC控制器系统.zip

    # 基于Arduino的CNC控制器系统 ## 项目简介 Grbl是一款开源的CNC(计算机数控机床)控制器固件,专为Arduino平台量身打造。它借助G代码(CNC机床编程的常用语言)对步进电机运动加以控制,还能对主轴、冷却液等附件进行操控。该系统通过串行通信与计算机或其他设备实现交互,具备实时命令执行、多轴运动控制、安全门监测等功能。 ## 项目的主要特性和功能 1. 多轴运动精准控制支持多轴运动控制,可精确调控机床运动。 2. 实时命令高效执行能实时执行移动、旋转、暂停等G代码命令。 3. 附件全面操控支持主轴的启动、停止及速度控制,同时可对冷却液等附件进行控制。 4. 安全门智能监测可实时监测安全门状态,保障机器工作时安全门处于关闭状态。 5. 便捷串行通信通过串行通信与计算机或其他设备交互,方便用户发送G代码命令并接收反馈信息。 6. 灵活参数设置提供丰富的设置参数,允许用户按需调整。

    2023-04-06-项目笔记 - 第四百四十九阶段 - 4.4.2.447全局变量的作用域-447 -2025.03.26

    2023-04-06-项目笔记-第四百四十九阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.447局变量的作用域_447- 2025-03-26

    (源码)基于Python的UAVCAN DSDL文件解析系统.zip

    # 基于Python的UAVCAN DSDL文件解析系统 ## 项目简介 本项目主要围绕Zubax GNSS 2展开,它是一款多功能高性能定位模块,可通过CAN总线、USB和UART进行通信。项目包含了Zubax GNSS 2的固件相关内容,同时有一个Python模块用于处理UAVCAN的DSDL定义文件,能从DSDL定义文件中解析出类型定义,支持UAVCAN协议的数据类型和通信。 ## 项目的主要特性和功能 ### Zubax GNSS 2硬件特性 具备先进的多系统GPSGLONASS接收器、高精度气压高度计和带热补偿的3轴罗盘。 支持多种标准协议,如UAVCAN(通过CAN总线)、NMEA 0183(通过USB和UART)和u Blox M8协议,确保与大多数现有软硬件兼容。 ### 固件相关功能 提供不同硬件版本对应的兼容固件版本,每个固件版本有专用分支。

Global site tag (gtag.js) - Google Analytics