如何修复 socket.timeout 和接收数据

How to fix socket.timeout and receiving data

我刚才写了那个程序,现在它停止工作了。每次我 运行 它都会说 "timed out"。当我将超时设置得更高(例如 10 秒)时也会发生此错误。

import sys
import socket

def traceroute(dest_addr, max_hops=30, timeout=0.2):
    proto_icmp = socket.getprotobyname('icmp')
    proto_udp = socket.getprotobyname('udp')
    port = 33434

    for ttl in range(1, max_hops+1):
        rx = socket.socket(socket.AF_INET, socket.SOCK_RAW, proto_icmp)
        rx.settimeout(timeout)
        rx.bind(('', port))

        tx = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, proto_udp)
        tx.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl)
        tx.sendto(bytes('', 'utf-8'), (dest_addr, port))

        try:
            data, curr_addr = rx.recvfrom(512)
            curr_addr = curr_addr[0]
        except socket.error as err:
            print (err)
            curr_addr = None
        finally:
            rx.close()
            tx.close()

        yield curr_addr

        if (curr_addr == dest_addr):
            break

if __name__ == "__main__":
    dest_name = "www.google.de"
    dest_addr = socket.gethostbyname(dest_name)

    print("traceroute to %s (%s)" % (dest_name, dest_addr))

    for i, v in enumerate(traceroute(dest_addr)):
        print("%d\t%s" % (i+1, v))

可能是您的计算机和 Google 之间的某个路由器没有发送您的代码无条件等待的 ICMP "host unreachable" 消息。

您发布的代码非常 "fragile" 并且它在 Internet 上往往会以奇怪而奇妙的方式中断。例如这里的例子是你 总是 在发送你的 UDP 数据包后立即等待 ICMP 消息,但你也可能会收到一个 UDP 数据包(如果端口恰好打开)或者什么也没有返回如果中间的路由器在 TTL 到期时静默丢弃数据包。

我建议使用 select (or similar) 来同时处理多个(即 UDP 和 ICMP)套接字的等待,或者您可以使用异步库来跟踪所有内容