scapy的实现中,yield的用法很好,它使得loop成为一个生成器,从而使得__iter__返回一个迭代器,那么yield的本质是什么呢?
保有yield的函数返回的是一个迭代器,而返回迭代器的也就是生成器了,用yield构造迭代器将会非常方便,总的来说,设yield函数返回一个迭代器iter1,只有在你显式的调用其next函数或者隐式作for-in操作时,yield函数中的yield值才会依次按照其yield的顺序返回出来,yield函数如果你使用yield N,那么这和return N是区别市很大的,如果仅仅return N的话,这个N就直接被返回了,它仅仅是一个值,而如果是yield N的话,虽然最终还是可以得到的还是N,但是你得到N的方式却变了,你只能通过iter的接口来得到N。yield只是在“塞”住了很多数据,只有iter的接口才能将其一个一个“拔”出来,在一个函数中,只要你yield了一个数据,那么就等于塞住了一个数据,将来需要用iter接口拔出它,比如以下的例子:
def test():
print "333"
yield 3
print "444"
yield 4
print "555"
yield 5
使用命令行运行之:
>>> def test():
... print "333"
... yield 3
... print "444"
... yield 4
... print "555"
... yield 5
...
>>> it=test() #没有任何输出
>>> a=it.next() #a的值是3,并且将输出333,后面的444,555依旧不输出,必须等待下次调用next以及下下次调用
333
>>> print a
3
隐式调用也一样:
>>> it=test()
>>> for k in it:
... print k
... break
...
333
3
>>> it=test()
>>> for r in it:
... print r
...
444
4
555
5
就是这样!有了yield的理论知识,接下来再看scapy的Packet类的__iter__这个函数:
00def __iter__(self):
01 def loop(todo, done, self=self):
02 if todo:
03 eltname = todo.pop()
04 elt = self.__getattr__(eltname)
05 if not isinstance(elt, Gen):
06 if self.fieldtype[eltname].islist:
07 elt = SetGen([elt])
08 else:
09 elt = SetGen(elt)
10 for e in elt:
11 done[eltname] = e
12 for x in loop(todo[:], done):
13 yield x
14 else:
15 if isinstance(self.payload,NoPayload):
16 payloads = [None]
17 else:
18 payloads = self.payload
19 for payl in payloads:
20 done2 = done.copy()
21 for k in done2:
22 if isinstance(done2[k], RandNum):
23 done2[k] = int(done2[k])
24 pkt = self.__class__(**done2)
25 pkt.underlayer = self.underlayer
26 pkt.overload_fields = self.overload_fields.copy()
27 if payl is None:
28 yield pkt
29 else:
30 yield pkt/payl
31 return loop(map(lambda x:str(x), self.fields.keys()), {})
在__str__中调用__iter__().next()返回的Packet实际上只有一个,那就是在13行返回的这个x,这是为何呢?在__iter__中总共有三个地方“塞”住了Packet(事实上可以归为两个,因为28行和30行可以视为一个),分别在13行,28行和30行,在__iter__的执行过程中,首先进入的是前半部分,只有在todo没有的时候才会进入后半部分else,可见if todo段是解决本层Packet对象的,如果todo没有了,在12行调用loop时才会进入到else段,因此else段是递归解决本层Packet对象的payload的,然后在28行或者30行“塞”一个Packet,可是如果执行到了28行或者30行,也塞住了Packet,那么接下来返回到哪里呢?想象一下当初是怎么进来的,是从12行进来的,于是返回12行,返回之后,直接就被“拔”出了,这是因为12行有一个for-in,拔出28行或者 30行塞入的Packet后紧接着又塞入一个,然后如果该层Packet对象的属性(也即todo链表)不止一个,还会进一步的返回上一个todo属性调用的loop,在for-in中又把刚刚在13行塞入的Packet给拔出了,最终__iter__返回的时候,其实只有最后一个Packet对象在13行被塞入。
对于直接调用__str__进而调用__iter__的Packet对象而言,进入else之后28行或者30行的yield被12行的for-in所抵消,最终在13行yield一个Packet对象,也是唯一的一个,对于进入19行的for-in而间接递归调用__iter__的所取得的payl这个Packet对象而言,其在13行最终yield的那个唯一的Packet对象被19行本身的for-in所抵消,这样最后就剩下了直接调用__str__函数的那个Packet对象本身。str函数的不断调用使得包的构建从下往上进行,每次上升一层,因为每次都会以已经处理完的Packet对象的payload再次调用str,从L3PacketSocket的send函数的outs.send中的str开始这一过程,随后在do_build中的p+str(self.payload)中继续这一过程,完成包的构建。
13行的yield x返回两个地方,一个是直接的__iter__().next()的调用,比如__str__中,另一个是隐式的for-in调用,其中也类似一个next的调用,比如19行的for-in,完全和13行的yield x“塞”“拔”抵消,另外12行的for-in,也是完全抵消,然而紧接着在13行又“塞”了一个,这就构成了一个循环,一个递归的循环。12-13行的“塞拔”是塞拔的同一个Packet对象,先拔再塞,拔的是28/29行塞入的对象或者13行塞入的对象,19行拔的是当前Packet对象的payload,而这个payload是在递归到上一层时在13行最后塞入的。懵了吗?递归加迭代就是这么...
分享到:
相关推荐
使用python来解析加密数据包,可通过pycharm安装Scapy-ssl_tls库文件,但库文件经常会安装失败,因此需要考虑直接安装python对应版本的Scapy-ssl_tls库文件
pcap-1.1-scapy-20090720.win32-py2.5
scapy-2.2.0是一款很有用的交互软件,功能很强大,下载后,在LINUX下解压,并安装,系统里要安装有PYTHON2.5以上版本~~
Python3 scapy模块 scapy-python3-0.14.tar
Scapy官方教程 没错,就是你要找的。Philippe Biondi and the Scapy community build your own tools with scapy
scapy交换机、路由器审计工具,支持自定义构造DHCP Discover、DHCP Offer、DHCP ACK 、DTP、802.1数据包
scapy最近版本源码,支持python版本2.7,3.4至3.8,不依赖python库;可用命令行交互及引用库形式,引用库需使用"from scapy import * "形式
虚假假货 使用Python和Scapy的伪无线接入点(AP)实现,旨在方便地测试802.11协议和实现。 该库正在开发中,目前仅支持开放的802.11网络。 动机 ...从那里开始,用scapy-fakeap设置基本AP非常简单,
基于python命令行修改数据包。基于python命令行修改数据包
scapy-icap scapy 的 ICAP/1.0 协议实现(从 invernizzi 的 scapy-http 复制代码) 用法 [root@user ~]$ scapy WARNING: No route found for IPv6 destination :: (no default route?) Welcome to Scapy (2.2.0-...
替补使用Scapy的小型python脚本使用Linux内置的Iptables进行ARP中毒和IP地址重定向,以执行MITM攻击。 目前,它的测试很有限,这意味着当心它不起作用。 另外,这会弄乱您的Iptable配置的规则,因此,如果您关心这种...
则考虑将pip的安装替换源替换为内部替代源,具体的操作步骤可以查考介绍博客使用方法运行程序Linux下首先需要切换到程序目录下,然后用管理员权限运行cd SCAPY-GUI-MASTERsudo python3 mainGUI.pyWindows下用管理员...
Scapy-osx 为OSX修补的最新Scapy版本。 在10.10.3测试 安装 更新端口树并安装依赖项 port selfupdate port install libdnet py27-libdnet py-readline py-gnuplot py-crypto py-pyx swig gnuplot graphviz 然后从...
About Scapy What is Scapy Scapy is a powerful interactive packet manipulation program. It is able to forge or decode packets of a wide number of protocols, send them on the wire, capture them, match ...
资源分类:Python库 所属语言:Python 资源全名:scapy_helper-0.1.12.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
wifi-deauth-detector python scapy- nodejs -mongodb
r2scapy - 一个用Scapy解码数据包的radare2插件
scapy 英文本 python可以调用scapy库模拟各种网络报文
参考官方文档,win64 scapy2.3.2 安装全部以及软件
scapy-2.2.0是一款很有用的交互软件,功能很强大,下载后,在LINUX下解压,并安装,系统里要安装有PYTHON2.5以上版本