tcl 中的服务发现

service discovery in tcl

我正在编写一个小 Tcl/Tk 脚本,它使用(自定义)网络应用程序(用 Python 编写)从一些中央存储中检索信息。

一切正常,但前提是事先知道网络服务器的地址。

所以我考虑添加某种服务发现,我的脚本会在本地网络上发现我的 Web 应用程序的所有 运行ning 实例,并自动使用它们。

我的第一个想法是使用 Zeroconf/Bonjour/Avahi,并让我的 Web 应用程序发布一个 _my-web-service._tcp 服务,其中包含实际的查询路径(tcl 客户端脚本应该用来访问数据)编码在 TXT 字段中:

avahi-publish-service MyService _my-web-service._tcp 8000 path=/data

不幸的是,我还没有找到 任何东西 将类似 zeroconf 的服务发现带入 Tcl 世界。

特别是,我正在查看 DNS entry on the Tcl Wiki,但这只会让我达到 mDNS(我目前不知道如何从那里继续到 zeroconf 堆栈)。

我不是特别受 Zeroconf/Bonjour/Avahi 约束,但想 运行 我在 Linux/Windows/macOS、 上的脚本保留我的构建要求最低(也就是说:如果我不必编译自己的包装器代码来与每个平台的服务发现接口,我会更喜欢它)。告诉用户从 3rd 方来源安装 Bonjour 或诸如此类的东西是可以容忍的。

In particular, I was looking at the DNS entry on the Tcl Wiki but that only gets me as far as mDNS (and i currently have no clue how to proceed from there to zeroconf stack).

您查看的是右角,但 Tcl'ers Wiki 处的代码片段似乎已过时。我很好奇,给了它一些爱。

这是使用以下方法测试的:

% package req Tcl
8.6.12
% package req dns
1.4.1
% package req udp
1.0.11

...并通过以下方式在 macOS 上宣布一项示范性服务:

dns-sd -R "Index" _http._tcp . 80 path=/index22.html

我通过检索 DNS-SD (RFC 6763) 特定记录,主要是 SRV 记录中的目标和端口,设法使用修补后的 dns 包发现了上述服务(s),以及来自相应 TXT 记录的额外内容(例如路径):

set instanceName "Index._http._tcp.local"
set tok [::dns::resolve $instanceName -protocol mdns -type SRV]
if {[::dns::wait $tok] eq "ok"} {

  set res [dict create {*}[lindex [::dns::result $tok] 0]]; # Pick first answer record, only!
  array set SRV [dict get $res rdata]
  ::dns::cleanup $tok
  
  
  set tok [::dns::resolve $instanceName -protocol mdns -type TXT]
  if {[::dns::wait $tok] eq "ok"} {
    array set TXT {}
    foreach txt [::dns::result $tok] {
      lassign [split [dict get $txt rdata] "="] k v
      set TXT($k) $v
    }
    ::dns::cleanup $tok
  }

  set tok [::dns::resolve $SRV(target) -protocol mdns -type A]
  if {[::dns::wait $tok] eq "ok"} {
    set res [dict create {*}[lindex [::dns::result $tok] 0]]; # Pick first answer record, only!
    puts "Service IP: [dict get $res rdata]"
    puts "Service port: $SRV(port)"
    puts "Service options: [array get TXT]"
  }
  ::dns::cleanup $tok
}

这将打印:

Service IP: 192.168.0.14
Service port: 80
Service options: path /index222.html

正在修补 tcllib 的 dns

来自 Tcl'ers Wiki 的片段需要修改,产生:

proc ::dns::UdpTransmit {token} {
  # FRINK: nocheck
  variable $token
  upvar 0 $token state

  # setup the timeout
  if {$state(-timeout) > 0} {
    set state(after) [after $state(-timeout) \
                          [list [namespace origin reset] \
                               $token timeout\
                               "operation timed out"]]
  }
  
  if {[llength [package provide ceptcl]] > 0} {
    # using ceptcl
    set state(sock) [cep -type datagram $state(-nameserver) $state(-port)]
    chan configure $state(sock) -blocking 0
  } else {
    # using tcludp
    set state(sock) [udp_open]
    if { $state(-protocol) eq "mdns" } {
      set state(-nameserver) "224.0.0.251"
      set state(-port)       5353
      chan configure $state(sock) -mcastadd $state(-nameserver);
    }
  }
  chan configure $state(sock) -remote [list $state(-nameserver) $state(-port)] \
      -translation binary \
      -buffering none;
  
  set state(status) connect
  chan event $state(sock) readable [list [namespace current]::UdpEvent $token]
  puts -nonewline $state(sock) $state(request)
  
  return $token
}

背景:

  • 这主要是为了反映udpAPI的变化(udp_confchan configure /socket/ -remote取代)
  • ...而且:原始片段没有加入多播 IP 来侦听 mDNS 响应 (-mcastadd)。
  • 除此之外,dns能够解码DNS资源记录(SRV,TXT)等。

(that is: i would prefer it, if i don't have to compile my own wrapper code to interface with the service-discovery for each platform)

这样,您不必与任何 third-party 库或 exec 连接到某些可执行文件 (dns-sd),但您必须将 Tcl/Tk 带有 platform-specific TclUDP 扩展名的脚本,作为 starpack 或 starkit,也许?