☰
astropy SAMP Hub 启动与停止完全指南:三种方式详解与底层原理
2026/10/14 2:02:17 网站建设 项目流程
  • 科学计算
  • 科研
  • 数据分析

【免费下载链接】astropy

Astronomy and astrophysics core library

项目地址:https://gitcode.com/gh_mirrors/as/astropy
点击查看免费下载

导读

SAMP(Simple Application Messaging Protocol,简单应用消息协议)是 IVOA(国际虚拟天文台联盟)定义的进程间通信协议,它通过一个本地运行的 Hub 进程,让 TOPCAT、SAO DS9、Aladin 等桌面天文工具与 Python 代码互相收发消息。本文以 docs/samp/example_hub.rst 为骨架,结合astropy.samp子包的源码实现,系统讲解在 astropy 中启动与停止 SAMP Hub 的三种途径——复用已有应用自带的 Hub、使用samp_hub命令行工具、以及用SAMPHubServer类编程式启动(含全部命令行参数与构造参数的表格式解析),并深入说明锁文件、超时线程、Web Profile 等底层机制,帮助你根据实际场景选择正确方案。

为什么需要先启动一个 SAMP Hub

astropy.samp是 SAMP V1.3 协议的 Python 实现,除 Standard Profile 外还支持 Web Profile。协议的基本工作方式是:本地主机上必须有一个正在运行的 SAMP "Hub" 进程,各客户端程序先连接到这个 Hub,再通过 Hub 互相转发消息(详见 docs/samp/index.rst)。

Hub 在整个会话中的角色类似于消息中枢:客户端通过它完成注册(register)、声明元数据(declare_metadata)、订阅消息类型(declare_subscriptions)、发送通知(notify)与同步调用(call)等。在大多数 SAMP 会话中,同时只会有一个 Hub 在运行。

值得留意的是,从 astropy 8.0 版本起,astropy.samp已被标记为弃用,官方建议迁移到pyvo.samp;但当前仓库中的实现依然完整可用,本文所述内容均基于仓库现状(弃用警告见 astropy/samp/init.py)。

启动 SAMP Hub 一共有三种方式,按适用场景从易到难逐一说明。

方式一:使用现有应用自带的 Hub

如果你只是想在日常桌面工具之间互传数据,最简单的做法是直接启动一个自带 Hub 的 SAMP 应用,例如:

  • TOPCAT(表格数据探索工具)
  • SAO DS9(图像显示与星表叠加工具)
  • Aladin Desktop(图像与星表可视化工具)

TOPCAT 和 Aladin 在找不到已运行 Hub 时会自动拉起一个 Hub(这一点在 docs/samp/example_table_image.rst 中有明确说明),因此先启动这类应用、再运行你的 Python 客户端即可,无需额外操心 Hub 的启动与停止。

这种方式的优点是完全不用接触 Hub 进程管理:Hub 的生命周期随宿主应用走,关闭应用即停止 Hub。缺点是你必须在桌面会话中保持该应用处于运行状态,且 Hub 的监听地址、端口等参数由该应用决定,不由你控制。

方式二:使用samp_hub命令行工具

astropy自带一个独立的命令行程序samp_hub,可以在自己的进程里运行一个常驻 Hub。它是三种方式中最常用、也最接近“开箱即用”的途径。

基本用法

直接运行即可启动一个 Hub:

$ samp_hub

查看全部可用选项:

$ samp_hub -h

停止服务:在前台终端中按下Control-C。

samp_hub的主函数位于 astropy/samp/hub_script.py,它使用argparse解析命令行参数,将解析结果透传给SAMPHubServer构造器后调用hub.start(False)以非阻塞方式启动,随后进入轮询循环:

  • 当 Hub 仍在运行(hub.is_running为真)时,以 0.01 秒间隔循环检查;
  • 捕获KeyboardInterrupt时调用hub.stop()优雅停机;
  • 捕获OSError时打印 I/O 错误并以状态码 1 退出。

全部命令行选项详解

以下选项均直接来自 hub_script.py 中的argparse定义,按功能分组列出。

基础连接选项

选项参数说明
-k,--secretCODE自定义 secret 码,写入 lockfile;不指定时由uuid.uuid1()自动生成
-d,--addrADDR监听地址(或 IP);默认为127.0.0.1(无网络时)或本机主机名(有网络时)
-p,--portPORT监听端口号;默认为 0,即由操作系统挑选空闲端口
-f,--lockfileFILE自定义 lockfile 文件路径
-w,--no-web-profile—以禁用 Web Profile 的方式运行 Hub(默认启用 Web Profile)
-P,--pool-sizeSIZE与客户端通信的 socket 连接池大小,默认 20

超时选项组(Timeout group)

选项参数说明
-t,--timeoutSECONDSHub 不活动超时(秒):超过该时长无任何活动则 Hub 自动关闭;默认 0,即永不过期
-c,--client-timeoutSECONDS客户端不活动超时(秒):超过该时长无活动的客户端将被 Hub 强制注销,并收到samp.hub.disconnect类型通知;默认 0,即客户端永不失效

日志选项组(Logging options)

选项参数说明
-L,--log-levelLEVELHub 日志级别,可取值即logging模块的全部级别名(CRITICAL、ERROR、WARNING、INFO、DEBUG 等),默认INFO
-O,--log-outputFILE将日志消息重定向到指定文件;默认为空,即输出到标准输出/标准错误

高级选项组(Advanced group)

选项参数说明
-l,--labelLABEL为 Hub 分配一个人类可读名称,写入 lockfile 的hub.label字段
-m,--multi—以多实例模式启动 Hub:使用随机命名的自定义 lockfile(见下文锁文件机制)

其中-m/--multi属于非标准的 Hub 行为,它允许多个 Hub 同时运行,每个 Hub 的 lockfile 放在用户主目录的.samp-1目录下,命名格式为samp-hub-<PID>-<ID>(PID 为 Hub 进程 ID,ID 为内部整数)。

命令行工具的测试验证

仓库中的测试 astropy/samp/tests/test_hub_script.py 演示了该工具的典型用法:以-m(多实例模式)与-w(禁用 Web Profile)启动,设置--log-level CRITICAL,并让hub_script(timeout=3)在 3 秒后自动停机,最后断言日志级别确实被设置为 CRITICAL。这印证了samp_hub各选项与hub_script的对应关系:-w对应web_profile=False,--log-level会直接作用于 astropy 全局日志器astropy.log。

方式三:编程式启动 Hub(高级用法)

对于需要把 Hub 嵌入到自己程序里的场景(例如嵌入 GUI 应用),可以绕过命令行,直接创建SAMPHubServer实例并调用其方法。在交互式 Python 提示符或脚本中均可:

>>> from astropy.samp import SAMPHubServer >>> hub = SAMPHubServer() >>> hub.start()

停止 Hub:

>>> hub.stop()

为什么文档不推荐普通用户使用这种方式

原文档明确提示:编程式启动一般不建议普通用户使用,因为它无法正确处理 Web SAMP 客户端连接;该方式主要留给需要在 GUI 中嵌入 Hub 的开发者。

从源码看,这一警告是有依据的:当web_profile=True(默认)且未提供web_profile_dialog时,Hub 在 Web 客户端请求连接时依赖web_profile_text_dialog在终端弹出文本式确认对话框(见 astropy/samp/hub.py 的_serve_forever循环与 astropy/samp/web_profile.py 中的web_profile_text_dialog实现)。而hub.start()默认以非阻塞线程方式运行(wait=False),在脱离交互式终端的环境里,这种终端交互确认并不适用。若确需保留 Web Profile,开发者应通过web_profile_dialog参数传入自定义 GUI 对话框实例,详见进阶文档 docs/samp/advanced_embed_samp_hub.rst(该文档还给出完整的 Tk 应用示例:继承WebProfileDialog、定时调用handle_queue()、实现show_dialog()后调用consent()/reject())。

SAMPHubServer 构造参数详解

以下参数定义见 astropy/samp/hub.py 的__init__签名,与samp_hub命令行选项一一对应:

参数默认值说明
secretNonelockfile 使用的 secret 码;不指定时用uuid.uuid1()生成
addrNone监听地址或 IP;无网络时默认127.0.0.1,有网络时默认本机主机名(源码中通过internet_on()判断并回退,见 hub.py)
port0XML-RPC 服务端口;0 表示由操作系统分配空闲端口
lockfileNone自定义 lockfile 名称
timeout0Hub 不活动超时(秒),大于 0 时自动停机;0 表示永不过期
client_timeout0客户端不活动超时(秒),大于 0 时自动注销不活动客户端;0 表示永不失效
mode'single''single'使用标准.samplockfile(桌面会话单实例);'multiple'使用.samp-1目录下的samp-hub-<UUID>非标准 lockfile
label''人类可读的 Hub 名称,写入 lockfile 的hub.label字段
web_profileTrue是否启用 Web Profile 支持
web_profile_dialogNone自定义确认对话框实例,替换终端文本式确认;实例会被注入queue_request与queue_result两个队列
web_port21012Web SAMP 端口;SAMP 规范要求 Web Profile 固定使用 21012,除测试外不应改动
pool_size20与客户端通信的 socket 连接池大小

start() 与 stop() 的底层行为

start(wait=False)的完整流程(hub.py):

  1. 若 Hub 已在运行或 lockfile 已存在,抛出SAMPHubError;
  2. 若启用 Web Profile,先启动 Web Profile HTTP 服务(_start_web_profile_server);
  3. 启动 Standard Profile 的 XML-RPC 服务;
  4. 通过create_lock_file创建 lockfile(写入 Hub 参数);
  5. 以 Hub 自身的身份注册为 SAMP 客户端并声明元数据(_setup_hub_as_client),使 Hub 也能收发消息;
  6. 启动后台线程(_start_threads);
  7. 若wait=True,则阻塞并join主线程——这一模式正是samp_hub独立脚本使用的阻塞式运行方式;wait=False(默认)则在后台线程中运行,适用于交互式 Python 会话与 GUI 嵌入。

stop()(hub.py)会先向所有订阅samp.hub.event.shutdown的客户端广播停机通知(_notify_shutdown),将_is_running置为False,校验 lockfile 中的 secret 后删除 lockfile,最后以 10 秒超时等待所有线程退出并重置内部状态。仓库测试 astropy/samp/tests/test_hub.py 验证了 Hub 的“启动→停止→再次启动”全生命周期,包括启用 Web Profile 的重复启动场景。

超时机制的实现

timeout与client_timeout分别由两个独立的守护线程负责(hub.py):

  • _timeout_test_hub:每 0.05 秒轮询一次,当距上次活动时间超过timeout时发出SAMPWarning警告并调用stop();
  • _timeout_test_client:遍历各客户端最后活动时间,对超过client_timeout的客户端发出警告、广播samp.hub.disconnect通知并强制注销。

两个线程仅在对应超时值大于 0 时才会被创建(见_start_threads),因此默认配置下不存在额外的线程开销。

lockfile 机制:Hub 如何被发现

Hub 的“存在性”通过 lockfile 对外宣告,相关逻辑集中在 astropy/samp/lockfile_helpers.py。要点包括:

  • 单实例模式(mode='single')下,lockfile 位于用户主目录的.samp文件;多实例模式(mode='multiple')下位于.samp-1目录,文件名为samp-hub-<UUID>;
  • 若环境变量SAMP_HUB设置为std-lockurl:前缀的地址,Hub 会改用该地址(须为file:协议);
  • 启动前会先清理失效 Hub 的垃圾 lockfile(remove_garbage_lock_files),并检查是否已有 Hub 在运行——若检测到其他 Hub 正在运行,则放弃启动;
  • lockfile 内容由SAMPHubServer.params属性生成(hub.py),包含samp.secret、samp.hub.xmlrpc.url、samp.profile.version、hub.id、hub.label等键。客户端正是通过读取这些键来连接 Hub。

相关配置项

astropy.samp在 astropy/samp/init.py 中定义了两个配置项:

  • use_internet(默认True):是否允许astropy.samp使用网络;
  • n_retries(默认10):通信失败时的重试次数。

这些配置会影响 Hub 在初始化时对监听地址的选择(addr依赖internet_on())以及消息投递的可靠性。

三种方式的对比与选型建议

方式适用场景优点注意事项
使用已有应用自带 Hub日常桌面工具互操作零配置、生命周期随应用需保持应用运行;参数不可控
samp_hub命令行独立常驻 Hub、脚本化工作流参数完整、进程隔离、Ctrl-C 即停需要单独管理进程
SAMPHubServer编程式嵌入 GUI、深度集成可在代码内控制全部行为默认 Web Profile 交互不便;普通用户不建议

选型建议:仅需在 TOPCAT、DS9、Aladin 之间互传数据时用方式一;需要稳定、可复现的 Hub 环境时用方式二(samp_hub),例如 docs/samp/example_table_image.rst 中发送表格与图像前先执行$ samp_hub的典型流程;只有当你确实要把 Hub 嵌入自己的应用程序(如 GUI)时,才使用方式三,并务必阅读进阶文档 docs/samp/advanced_embed_samp_hub.rst 处理 Web Profile 的连接确认对话框。

进一步阅读

  • docs/samp/example_hub.rst:本文的原始骨架文档;
  • docs/samp/advanced_embed_samp_hub.rst:在 GUI 中嵌入 Hub 的完整示例(Tk + WebProfileDialog);
  • docs/samp/example_table_image.rst:启动 Hub 后收发表格(table.load.votable)与图像(image.load.fits)的实战流程;
  • docs/samp/example_clients.rst:SAMPClient与SAMPIntegratedClient的客户端实现细节;
  • astropy/samp/hub_script.py 与 astropy/samp/hub.py:samp_hub与SAMPHubServer的源码实现;
  • astropy/samp/tests/test_hub_script.py 与 astropy/samp/tests/test_hub.py:对应的自动化测试用例。
  • 科学计算
  • 科研
  • 数据分析

【免费下载链接】astropy

Astronomy and astrophysics core library

项目地址:https://gitcode.com/gh_mirrors/as/astropy
点击查看免费下载
上一篇:UIEffectTweener组件终极指南:无需代码实现Unity UI动画特效的完整教程
下一篇:Redisson 在哨兵模式下获取分布式锁的常见错误及解决方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询