Python: 线程化ARP ping的奇怪输出

0 投票
1 回答
696 浏览
提问于 2025-04-17 23:00

谢谢你花时间来看这个!

我遇到的问题是关于我这个多线程的ARP脚本输出的内容。我想要实现的是把每个活着的主机的IP地址、MAC地址和网络接口卡的厂商信息输出到命令提示符上。

我有一个旧的ARP脚本,没有使用多线程,运行大约需要90秒,输出的内容正是我想要的。

下面是我基于之前那个脚本写的新脚本,加入了多线程。不幸的是,我不知道为什么输出中没有任何值。如果有人能帮我,我将非常感激!

提前谢谢你!

def arp2(ip):

    # An ARP scanner for the network.
    ips = []

    global ans, unans
    ans, unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=ip), timeout=2, verbose=0)

    for snd, rcv in ans:
    #Assign MAC address and IP address to variables mac and ipaddr

        mac = rcv.sprintf(r"%Ether.src%")
        ipaddr = rcv.sprintf(r"%ARP.psrc%")

        #Get NIC vendor code from MAC address
        niccode = mac[:8]
        niccode = niccode.upper()

        print ips
        ips.append("end")

        #ARPips file amendments
        with open( 'C:\Python26\ARPips.prn', 'w+') as f:
            f.write("\n".join(map(lambda x: str(x), ips)) + "\n")

        #String lookup for NIC vendors. DO NOT CHANGE 'r' TO ANY OTHER VALUE.
        with open('C:\Users\TomVB\Desktop\OID2.prn', 'r') as file:
            for line in file:
                if niccode in file:
                    return mac, ipaddr, line[8:]




def main():

    print "Discovering..."
    print ""
    print "MAC Address \t \t  IP Address \t  NIC Vendor"


    pool = Pool(processes=12)

    Subnetlist = []

    for i in range(255):
        Subnetlist.append(str(IPInt+str(i)))

    global ARPresults
    ARPresults = pool.map(arp2, Subnetlist)

    pool.close()
    pool.join()


    print "\n".join(ARPresults)

if __name__ == '__main__':
    main()

这个脚本给我的输出是:

Mac Address    IP address      NIC Vendor

[][]

[]

[]

[]
 []
[][]
[]

[]  

然后大约有200行这样的内容。

1 个回答

0

首先,看起来你在使用多进程,而不是线程。这两者的工作方式是完全不同的,我建议你了解一下这点。不过,针对你现在遇到的问题,原因在别的地方。

arp2 方法是并行执行的。我在这个方法里看到两个问题:

print "%s \t  %s  \t  %s" % (mac, ipaddr, line[8:])

这个语句是输出到标准输出的。在我们的代码中,可能会有多达12个进程同时执行这个语句。Python并不能保证print语句是原子操作,也就是说,可能会出现一个进程写了一半的内容,另一个进程接着写,这样就会导致输出结果混乱。

同样的情况也适用于

with open( 'C:\Python26\ARPips.prn', 'w+') as f:
    f.write("\n".join(map(lambda x: str(x), ips)) + "\n")

这里也没有保证进程之间不会互相干扰,文件内容可能会被搞乱。

最简单的解决办法是在arp2方法中不要进行任何文件或控制台的输出。可以改为返回结果。pool.map会安全地收集这些结果,工作方式和普通的map函数一样。然后你可以再把结果输出到文件或控制台。

如果你想在扫描进行时看到输出,就需要同步这些进程(比如使用multiprocessing.Lock),确保同一时间只有一个进程在写入或打印。

另外:

  • 在使用Windows风格路径的字符串前加个'r':x = r'C:\Users\TomVB\Desktop\OID2.prn'。因为在Python中反斜杠是用来转义的。

  • C:\Users\TomVB\Desktop\OID2.prn的内容加载到一个dict中,这样会快很多。

  • map(lambda x: str(x), ips)map(str, ips) 是等价的。

撰写回答