我需要在Twisted代码中从网络接口接收原始数据包。数据包将没有正确的IP或MAC地址,也没有有效的报头,因此我需要原始的东西。
我尝试研究twisted.pair
,但无法弄清楚如何使用它来获取原始界面。
通常,我会使用scapy.all.sniff
。但是,这很困难,因此我不能仅将它与Twisted一起使用。 (我也不能将scapy.all.sniff
用于超时和繁忙循环,因为我不想丢失数据包。)
一个可能的解决方案是在线程中运行scapy.all.sniff
,并在收到数据包时以某种方式回调Twisted。这似乎有点不雅(而且我也不知道该怎么做,因为我是一名Twisted初学者),但是如果我找不到更好的东西,我可能会解决。
答案 0 :(得分:-1)
您可以运行分布式系统,并将数据通过中央排队系统传递。遵循Unix的哲学,创建一个可以完成一些任务并且很好完成的应用程序。创建一个嗅探数据包的应用程序(您可以在此处使用scapy
,因为如果阻塞任何内容都没有关系),然后将它们发送到队列(RabitMQ,Redis,SQS等),然后让另一个应用程序处理队列中的数据包。这种方法应该让您头痛的次数最少。
如果您需要在单个应用程序中运行所有程序,则线程/多处理是唯一的选择。但是,您需要遵循一些设计模式。您还可以将以下代码分解为单独的功能,并使用专用的排队系统。
from threading import Thread
from time import sleep
from twisted.internet import defer, reactor
class Sniffer(Thread):
def __init__(self, _reactor, shared_queue):
super().__init__()
self.reactor = _reactor
self.shared_queue = shared_queue
def run(self):
"""
Sniffer logic here
"""
while True:
self.reactor.callFromThread(self.shared_queue.put, 'hello world')
sleep(5)
@defer.inlineCallbacks
def consume_from_queue(_id, _reactor, shared_queue):
item = yield shared_queue.get()
print(str(_id), item)
_reactor.callLater(0, consume_from_queue, _id, _reactor, shared_queue)
def main():
shared_queue = defer.DeferredQueue()
sniffer = Sniffer(reactor, shared_queue)
sniffer.daemon = True
sniffer.start()
workers = 4
for i in range(workers):
consume_from_queue(i+1, reactor, shared_queue)
reactor.run()
main()
Sniffer
类在Twisted的控制范围之外开始。请注意sniffer.daemon = True
,这是为了在主线程停止时停止线程。如果将其设置为False
(默认值),则仅当所有线程都结束时,应用程序才会退出。根据手头的任务,这可能或不一定总是可能的。如果您可以从嗅探中休息一下以检查线程事件,那么您也许能够以更安全的方式停止线程。
self.reactor.callFromThread(self.shared_queue.put, 'hello world')
是必需的,以便放入队列中的项目发生在主反应堆线程中,而不是Sniffer
执行的线程中。这样做的主要好处是,将对来自线程的消息进行某种形式的同步(假设您计划扩展以嗅探多个接口)。另外,我不确定DeferredQueue
对象是否是线程安全的:)我将它们视为不是线程安全的。
由于在这种情况下Twisted不管理线程,因此开发人员执行线程至关重要。注意worker
循环和consume_from_queue(i+1, reactor, shared_queue)
。该循环确保仅所需数量的工人在处理任务。在consume_from_queue()
函数内部,shared_queue.get()
将等待(无阻塞),直到将某个项目放入队列中,打印该项目,然后安排另一个consume_from_queue()
。