【发布时间】:2019-12-15 15:57:19
【问题描述】:
我有一个UDPSocket 实例:
io = UDPSocket.new
io.connect "8.8.4.4", 53
它通过端口 53 连接到 DNS 服务器,发送 DNS 查询并检索结果。 DNS 内置了指针形式的消息压缩,参见RFC 1035, 4.1.4。消息压缩。资源记录可以包含指向问题域的消息偏移量,而不是域名。这样就不必为每条记录重复域名。
我在我的资源记录类中实现了如下:
def self.from_io(io : IO, format : IO::ByteFormat) : self
domain = ""
loop do
codepoint = UInt8.from_io io, format
break if codepoint == 0
if codepoint >= 192 # if the octet starts with 11 as defined in the rfc
current_pos = io.pos
pointer = UInt8.from_io io, format
io.seek(pointer)
# read the string...
end
# ...
end
end
这不起作用,因为UDPSocket 没有实现IO#pos 和IO#seek:
Unhandled exception: Unable to pos
为了解决这个问题,我创建了一个使用 IO::Memory 的子类:
class DNS::DNSSocket < UDPSocket
def initialize(family : Socket::Family = Socket::Family::INET)
super family
@memory = IO::Memory.new
end
def read(slice : Bytes)
if slice.size + pos > @memory.size
super slice
@memory.write slice
else
@memory.read slice
end
slice.size
end
def pos
@memory.pos
end
def pos=(value)
@memory.pos = value
end
def seek(offset, whence : Seek = IO::Seek::Set)
@memory.seek offset, whence
end
def clear
@memory.clear
end
end
我的问题如下:
-
这是一个好的解决方案,还是您知道更优雅的方法?
-
IO::Memory实例需要在每条消息后重置。是否可以在我的 DNSSocket 实现中的数据报(数据包)的末尾或开头调用clear?我也可以在我的消息解析器中调用它,但我不想这样做。
【问题讨论】:
标签: sockets dns crystal-lang