我在这里说实话:在功能编程方面,我从来没有比阅读或解决简单问题更进一步。尽管喜欢简洁,易于维护的源代码,我从未找到使用范例的理由。直到今天:我想在Python中实现一些网络工具(如traceroute
或ping
),尽可能“功能性”(在scapy
的帮助下,{ {1}}和functools
。首先,itertools
:
ping
然后,def tcp_ping(destination_ip, destination_port, n_probes=10, timeout=1):
source_ports = [randint(49152, 65535) for i in range(n_probes)]
probes = IP(dst=destination_ip)/TCP(sport=source_ports, dport=destination_port, flags='S')
responses = map(partial(sr, timeout=timeout, verbose=0), probes)
answered = filter(lambda x: len(x[0]) > 0, responses)
lost = filter(lambda x: x not in answered, responses)
rtts = map(lambda x: int(1000 * (x[0][0][1].time - x[0][0][0].sent_time)), answered) or [0]
return dict(loss=float(len(lost))/n_probes,
min_rtt=min(rtts),
max_rtt=max(rtts),
avg_rtt=mean(rtts),
std_rtt=std(rtts))
:
traceroute
现在,问题:
def takeuntil(predicate, iterable):
for x in iterable:
yield x
if predicate(x):
break
def traceroute_probes(destination_ip, destination_port):
ttl = 1
while ttl <= 255:
p = IP(dst=destination_ip, ttl=ttl)/TCP(dport=destination_port, flags='S')
yield p
ttl = ttl + 1
def is_finalhop(x):
return (len(x[0]) > 0 and
not x[0][0][1].haslayer('ICMP'))
def hop_ip_latency(x):
if len(x[0]) > 0:
return (x[0][0][0].ttl,
x[0][0][1].src,
max(0, int(1000 * (x[0][0][1].time - x[0][0][0].sent_time))))
else:
return (x[1][0][0].ttl, '*', 0)
def tcp_traceroute(destination_ip, destination_port, timeout=1):
responses = takeuntil(is_finalhop,
imap(partial(sr, timeout=timeout, verbose=0),
traceroute_probes(destination_ip,
destination_port)))
return map(hop_ip_latency, responses)
)而不会引入不必要的副作用?traceroute
(与世界的接口)行为(例如,根据RTT改变sr
中的超时)而不会陷入命令式/面向对象的陷阱?ping
添加到Python的takeuntil
?