首页 / 资讯中心 / 文章详情

Angry IP Scanner(ipscan)开发者指南:Gradle 构建、架构与插件系统全解析

Angry IP Scanner(ipscan)开发者指南:Gradle 构建、架构与插件系统全解析 ★ FEATURED ARTICLE
网络【免费下载链接】ipscanAngry IP Scanner - fast and friendly network scanner项目地址https://gitcode.com/gh_mirrors/ip/ipscan点击查看免费下载本篇技术指南以仓库根目录的 AGENTS.md 为骨架面向想要理解、构建、测试和扩展 Angry IP Scanneripscan的开发者完整讲解其非标准 Gradle 构建体系、测试策略、轻量级依赖注入架构、平台特定代码、插件加载机制与各平台打包流程。读完本文你将掌握从源码构建各平台二进制、运行定向测试、编写自定义 Pinger 插件以及理解 SWT/JNA 集成原理的完整技术路径。项目概览一个基于 Java SWT 的跨平台网络扫描器Angry IP Scanner仓库目录名ipscan是一个用 Java 编写的跨平台网络扫描器GUI 采用 Eclipse SWTStandard Widget Toolkit调用各平台原生控件许可证为 GPLv2。它具备快速扫描 IP 段、探测端口、抓取主机名/MAC 地址/Web 检测信息、导出多种格式结果等能力。从源码层面看有四个关键定位信息入口点net.azib.ipscan.Main实现文件为 src/net/azib/ipscan/Main.java。其main()方法依次完成创建GUI、通过Labels.initialize(locale)初始化国际化标签、用new ComponentRegistry().init()启动依赖注入容器、处理命令行参数最后gui.showMainWindow(injector, args.length 0)展示主窗口。包根net.azib.ipscan源码位于src/目录下。测试镜像测试树位于test/与src/下的包结构一一对应例如test/net/azib/ipscan/core/net/镜像src/net/azib/ipscan/core/net/。在开发环境直接运行Main时注意两个 JVM 参数要求源码注释中明确给出# 指定日志配置文件config/logging.properties 位于仓库 config/ 目录 -Djava.util.logging.config.fileconfig/logging.properties # Mac 上必须添加否则 SWT 无法工作 -XstartOnFirstThread构建系统Gradle 9.5 Wrapper 与 Java 21项目使用 Gradle 9.5 Wrapper仓库根目录的./gradlew脚本与gradle/wrapper/gradle-wrapper.propertiesJava 21 作为源码/目标编译版本CI 环境使用 Java 25Liberica 发行版。非标准源码布局这是本项目最需要留意的一点项目并未采用惯例的src/main/java布局而是在 build.gradle 中显式配置了 sourceSetssourceSets { main { java { srcDirs src } resources { srcDirs config, src, resources } } test { java { srcDir test } resources { srcDir test } } }也就是说主源码来自src/测试源码来自test/而资源则由config/、src/、resources/三处合并进入主资源。新增源码或资源文件时需要放在上述目录中而非新建src/main/java之类的路径。常用构建命令./gradlew current # 为当前 OS/arch 构建 jar ./gradlew test # 运行全部测试 ./gradlew info # 列出所有构建目标 ./gradlew clean # 清理构建目录平台相关目标包括linux64仅 Linux 64 位、any平台无关构建、win64、macX86、macArm64以及聚合目标mac macX86 macArm64、linux any linux64、win-installerWindows 安装包。构建产物输出到build/libs/可用java -jar jar-file直接运行。build.gradle中的info任务会打印各目标的具体含义例如any不打包 SWT依赖操作系统提供的libswt包即可运行实验性适合 ARM/Raspbianwin-installer打包包含内置 JRE 的 Windows 安装程序。版本号不是硬编码的而是通过git describe --tags动态获取见build.gradle第 30 行获取失败时回退为unknown。Ubuntu 构建依赖在 Ubuntu 上构建 Linux 包需要以下系统包sudo apt install openjdk-21-jdk rpm fakeroot其中rpm用于生成.rpm包fakeroot用于以非 root 方式调用dpkg-deb生成.deb包。代码风格与测试策略代码风格仓库约定使用4 空格缩进AGENTS.md 中唯一明确的风格条款。从 src/net/azib/ipscan 各源码文件可以看到一致的风格字段与局部变量普遍使用varJava 10 类型推断类注释统一标注author。测试框架JUnit 4 Mockito 2.x测试采用 JUnit 4junit:junit:4.13.2 Mockito 2.xorg.mockito:mockito-core:2.23.0测试类使用Test、Before注解。依赖声明见 build.gradle 第 74-75 行。./gradlew test # 运行全部测试 ./gradlew test --tests net.azib.ipscan.core.net.* # 运行单个包 ./gradlew test --tests *PingFetcherTest # 运行单个测试类Mac 上的特殊限制由于 macOS 的 Cocoa 线程限制涉及 GUI 的测试在 Mac 上会被排除只运行net.azib.ipscan.core.net.*。这由 build.gradle 中的test任务实现test { jvmArgs --add-opens, java.base/java.netALL-UNNAMED if (platform.startsWith(mac)) { println(WARNING: tests that touch GUI will fail on Mac due to Cocoa restrictions and Gradle unable to run tests on main thread) filter { includeTestsMatching net.azib.ipscan.core.net.* } } }在 Linux CI 上SWT 相关测试通过xvfb-run -a在无头headless虚拟显示器下运行。Pinger 测试的网络依赖Pinger 测试需要真实网络访问存活alive测试 ping127.0.0.1死亡dead测试 ping192.168.99.253。这意味着在无网络或防火墙拦截 ICMP 的环境下相关测试可能失败运行前需确认网络环境。测试中的 DI 模式需要组件的测试使用new ComponentRegistry().init(false)初始化——false参数跳过 GUI 注册得到一个 headless 的注入器。这在大量测试中都能看到例如 test/net/azib/ipscan/di/InjectorTest.java、test/net/azib/ipscan/exporters/ExportProcessorTest.java 等。架构轻量级依赖注入容器项目最大的架构特色是自研的轻量级依赖注入容器位于net.azib.ipscan.di.Injector实现文件为 src/net/azib/ipscan/di/Injector.java。基于构造函数的注入Injector采用构造函数注入创建实例时选取参数最多的公开构造函数max(comparing(Constructor::getParameterCount))然后递归解析其依赖并实例化。全程无需任何注解。核心逻辑如下createInstance方法private T T createInstance(ClassT type) { var constructor (ConstructorT) stream(type.getConstructors()) .max(comparing(Constructor::getParameterCount)) .orElseThrow(() - new InjectException(No public constructors)); try { return constructor.newInstance(resolveDeps(constructor)); } catch (Throwable e) { throw new InjectException(Cannot create type.getName() , deps: Arrays.toString(constructor.getGenericParameterTypes()), e); } }resolveDeps还会特殊处理Collection类型的参数如果构造函数参数是ListSomeInterface这类泛型集合则通过requireAll()注入容器中所有该接口的实现。例如ExporterRegistry就能一次性拿到全部 Exporter 实现。三个装配模块注入装配分散在三个注册类中注册类职责实现文件ComponentRegistryfetchers、exporters、pingers 等核心组件src/net/azib/ipscan/config/ComponentRegistry.javaConfigModule配置单例Config、Labels、Preferences、ScannerConfig、OpenersConfig、FavoritesConfigsrc/net/azib/ipscan/config/ConfigModule.javaGUIRegistrySWT 控件与 GUI 组件位于gui/包启动引导方法是ComponentRegistry.init(boolean withGUI)ComponentRegistry.java 第 51-66 行init(true)用于正常启动额外注册 GUI 组件并加载插件init(false)用于测试的无头模式。ComponentRegistry.register()中值得注意的代码展示了平台特定 fetcher 的选择方式——通过反射按平台拼接类名实例化i.register(MACFetcher.class, (MACFetcher) Class.forName(MACFetcher.class.getPackage().getName() (Platform.WINDOWS ? .WinMACFetcher : Platform.LINUX ? .LinuxMACFetcher : .UnixMACFetcher)).newInstance());平台检测与平台特定代码平台判断集中在net.azib.ipscan.config.Platformsrc/net/azib/ipscan/config/Platform.java基于os.name系统属性提供布尔常量MAC_OSos.name含 OS XLINUXos.name含 LinuxWINDOWSos.name以 Windows 开头CRIPPLED_WINDOWSWindows 且os.version在 [5.1, 6.1) 区间内即 XP/Vista/7 这类缺少 RawSockets、TCP 限速等能力的旧 Windows平台相关的核心组件包括平台特定 fetcherWinMACFetcher、LinuxMACFetcher、UnixMACFetcher在 DI 装配时通过反射选择见上文ComponentRegistry。Windows 专属 pingerWindowsPinger、WinIpHlp以及 JNA 接口WinIpHlpDll、WinKernel32通过 JNA 调用原生 API。关键包结构与职责包用途config/配置、Labelsi18n、平台检测、ComponentRegistryDI 装配core/扫描引擎、扫描状态机、结果对象core/net/PingersICMP、TCP、UDP、ARP、Windows 专用di/自研 DI 容器exporters/结果导出格式CSV、TXT、XML、SQL、IPListfeeders/IP 范围输入源range、random、file、rescanfetchers/数据抓取器ping、hostname、ports、MAC、web detect 等gui/SWT GUIMainWindow、对话框、菜单、feeder/fetcher 面板util/工具类围绕这些接口可以梳理出扫描引擎的数据流Feeder 生成 IP 地址序列 → ScannerDispatcherThread 派发 → Scanner 逐个执行选中的 Fetcher → 结果写入 ScanningResult → Exporter 序列化为文件。Feeder 接口src/net/azib/ipscan/feeders/Feeder.java提供hasNext()/next()/percentageComplete()/getInfo()实现应保持不可变语义。Fetcher 接口src/net/azib/ipscan/fetchers/Fetcher.java要求实现线程安全且无状态实例在扫描线程间共享scan()返回的值可为NotAvailable或NotScanned特殊值。Exporter 接口src/net/azib/ipscan/exporters/Exporter.java定义了回调式调用序列start → setFetchers → nextAddressResult… → endExporter 实例通过克隆prototype 模式创建。Pinger 接口src/net/azib/ipscan/core/net/Pinger.java扩展了Plugin与AutoCloseable通过ping(subject, count)探测主机存活。Scanner.scan()src/net/azib/ipscan/core/Scanner.java 第 40-67 行遍历当前选中的所有 fetcher逐列填充结果未扫描被中断时写入NotScanned.VALUE抓取返回null且线程未中断时写入NotAvailable.VALUE。插件系统三种加载途径与信任机制插件plugin是扩展ipscan能力的主要手段。所有插件必须实现net.azib.ipscan.core.Plugin接口src/net/azib/ipscan/core/Plugin.java并进一步实现一个或多个具体接口如Fetcher、Exporter、Pinger、Feeder。加载逻辑集中在 src/net/azib/ipscan/core/PluginLoader.java。三种加载途径PluginLoader.getClasses(trustVerifier)依次尝试以下三个来源系统属性指定通过-Dipscan.pluginscom.example.MyPlugin传入逗号分隔的类名列表。这些类必须位于应用 classpath 上适合开发调试阶段对应loadPluginsSpecifiedInSystemProperties类名按\\s*,\\s*拆分。与应用二进制同目录的 JAR扫描 ipscan 二进制jar 或 exe所在目录下除自身以外的所有.jar文件要求 JAR 的META-INF/MANIFEST.MF中以IPScan-Plugin或IPScan-Plugins主属性列出插件类名。用户目录$HOME/.ipscan/加载该目录下的 JAR规则同途径 2。JAR 插件通过自定义的PluginClassLoader继承URLClassLoader加载并且可以自带messages.properties实现插件级国际化加载时通过Labels.getInstance().load(loader)并入标签表。插件信任验证从ComponentRegistry.init(true)可以看到正常启动时加载插件会经过PluginTrustVerifiersrc/net/azib/ipscan/config/ComponentRegistry.java 第 68-91 行对每个插件 JAR 弹出 SWT 对话框询问用户是否信任选择会记录到 Preferences 的trustedPlugins/rejectedPlugins键中按|分隔的 canonical path 列表后续加载同一 JAR 时直接命中缓存不再询问。插件若同时实现了Pinger还会被注册进PingerRegistry可以直接被扫描流程选用。国际化i18n所有 UI 文案以属性文件形式存放resources/messages.properties—— 英文兜底fallbackresources/messages_lang.properties—— 各语言覆盖文件。代码通过Labels.getLabel(key)访问实现见 src/net/azib/ipscan/config/Labels.java。Labels是单例initialize(Locale)负责按 locale 加载加载逻辑会依次尝试messages_locale.properties→messages_language.properties都失败则回退到英文。支持的语言列在Labels.LANGUAGES常量中包括en、ru、de、zh_CN、zh_TW、ja等 18 项。新增 UI 文案的约定先把 key 加进messages.properties再补充其他语言的翻译否则其他语言下会输出 key 本身并记录 warning。打包流程从 JAR 到各平台安装包build.gradle通过packageTask(platform, doMore)为每个平台生成打包任务产物均落在build/libs/。JAR 的 Manifest 会写入Main-Class: net.azib.ipscan.Main、Implementation-Version来自 git describe以及从 SWT JAR 读取的SWT-OS/SWT-ARCH属性。Linux.deb 与 .rpm仅 Ubuntu.deb使用fakeroot dpkg-deb -Zxz从ext/deb-bundle模板打包DEBIAN/control中的VERSION/ARCH/DEPENDS占位符在打包时被替换any平台包会额外依赖libswt-gtk-4-java, libswt-cairo-gtk-4-jni系统 SWT 库。.rpm通过rpmbuild打包spec 文件位于 ext/rpmbuild/SPECS/ipscan.spec打包时替换RPM_VERSION/VERSION占位符。Windowsexe launcher NSIS 安装器Windows 可执行文件并非编译而来而是将原生 launcher 与 JAR 二进制拼接ext/win-launcher/launcher.exe对应 C 源码 ext/win-launcher/launcher.c在前、JAR 在后通过ant.concat合并为ipscan-version-win.exe。win-installer任务会下载 NSIS 3.08通过makensis编译 ext/win-installer/Installer/Installer.nsi 生成ipscan-version-setup.exe并调用jlink打入精简 JRE。Mac.app bundle jlink JREMac 打包流程基于 ext/mac-bundle/Angry IP Scanner.app 模板将平台 JAR 移入.app/Contents/MacOS/并用jlink生成精简 JRE--add-modules只包含java.base, java.prefs, java.logging, jdk.crypto.ec等模块。若设置了APPLE_USER/APPLE_PASSWORD环境变量还会调用xcrun altool --notarize-app提交 Apple 公证。ProGuard 混淆所有平台 JAR 打包后都会经过 ProGuard 7.8.1 最小化处理任务platform.min规则配置在 ext/swt.pro 与 ext/jna.prodontobfuscate、dontoptimize保留net.azib.ipscan.**的公开类与方法混淆后的*.min.jar会替换原 JAR。这解释了为什么发布产物比依赖原始体积小很多。数据文件与用户偏好MAC 厂商数据库resources/mac-vendors.txt是根据 IEEE OUI 数据生成的 MAC 厂商前缀库供MACVendorFetcher查询。更新方式./update-mac-vendors.shmacOS 上执行该脚本需要先安装 GNU sedbrew install gnu-sed。用户偏好存储用户偏好不保存在项目文件里而是通过java.util.prefs.Preferences存储于系统级偏好节点ipscan下。以扫描相关配置为例src/net/azib/ipscan/config/ScannerConfig.java 列出了全部偏好项及其默认值键默认值说明maxThreads0最大扫描线程数0 表示自动threadDelay20线程启动间隔msscanDeadHostsfalse是否扫描未存活主机selectedPingerpinger.windowsWindows/pinger.java其他当前选择的 pingerpingTimeout2000Ping 超时mspingCount3每台主机 Ping 次数skipBroadcastAddressestrue是否跳过广播地址portTimeout2000端口探测超时msadaptPortTimeout!CRIPPLED_WINDOWS是否自适应端口超时minPortTimeout100最小端口超时msportString80,443,8080默认探测端口useRequestedPortstrue是否只使用指定端口notAvailableText/notScannedText本地化文本结果表中的占位文本Gradle 构建的怪癖quirk备忘AGENTS.md 最后列举了几个容易踩坑的构建细节这里结合 build.gradle 与 gradle.properties 逐一说明--add-opens java.base/java.netALL-UNNAMED写在 gradle.properties 的org.gradle.jvmargs中同时在test任务中通过jvmArgs重复传入。这是 JNA/反射访问java.net内部类所必需的移除会导致启动或测试时报IllegalAccessError。SWT 依赖被全局排除all*.exclude module: org.eclipse.swt用于排除 Maven 上失败的传递性 SWT 依赖平台特定 SWT 通过 Gradle 配置linux64/win64/macX86/macArm64按需引入版本统一为3.134.0。平台配置控制原生库打包jna配置net.java.dev.jna:jna:5.9.0被win64.extendsFrom(jna)继承打包时各平台配置决定哪些原生库进入最终 JAR例如非 Windows 平台会排除net/azib/ipscan/core/net/Win*与net/azib/ipscan/fetchers/Win*类以及不需要的.dll/.so/.jnilib。小结一张路线图围绕 AGENTS.md从构建到扩展的完整路线是构建./gradlew current为当前平台产出 JAR若报 JNA 反射错误检查--add-opens是否生效测试./gradlew test运行全部测试注意 Mac 上仅执行core.net包、Pinger 测试需要网络连通理解架构以ComponentRegistry.init()为入口顺着Injector的构造函数注入理解 fetcher/exporter/pinger 的装配关系扩展实现Plugin 具体接口通过-Dipscan.plugins、同目录 JAR 或~/.ipscan/三种途径加载发布用linux64/any/win64/macX86/macArm64/win-installer生成各平台安装包所有 JAR 经过 ProGuard 最小化。这份 AGENTS.md 本身也是为 AI 编码助手准备的项目说明书本文则将其中的要点与源码实现一一对应作为开发者快速上手的深度参考。赞分享网络【免费下载链接】ipscanAngry IP Scanner - fast and friendly network scanner项目地址https://gitcode.com/gh_mirrors/ip/ipscan点击查看免费下载相关推荐终极指南Angry IP Scanner开发入门——从零理解Java网络扫描器架构设计终极指南Angry IP Scanner开发入门——从零理解Java网络扫描器架构设计 Angry IP Scanner 是一款快速友好的网络扫描工具采用J网络Angry IP Scanner网络拓扑发现构建完整的网络设备地图Angry IP Scanner网络拓扑发现构建完整的网络设备地图 想要快速了解你的网络中有哪些设备吗Angry IP Scanner就是你的终极网络发现工网络Prompt Engineering 学习地图从入门到 AI 智能体Prompt Engineering 学习地图从入门到 AI 智能体 同一个问题问两次大模型给出的回答可能天差地别想让 AI 调用外部工具它却只会口头承文档教程提示工程大模型人工智能RAGAI Agent上一篇aiohttp 贡献指南从开发环境搭建、测试与覆盖率到 Changelog 与 Backport 的完整开发者工作流下一篇Diem 区块链的链上版本管理DiemVersion 模块源码与实战解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站