wifijammer源码分析二

主要详细学习代码中以下几个模块

from signal import SIGINT, signal
import argparse
import socket
import struct
import fcntl

signal模块

信号(signal)-- 进程之间通讯的方式,是一种软件中断。一个进程一旦接收到信号就会打断原来的程序执行流程来处理信号。
几个常用信号:
SIGINT 终止进程 中断进程 (control+c)
SIGTERM 终止进程 软件终止信号
SIGKILL 终止进程 杀死进程
SIGALRM 闹钟信号

import os    
import signal    
from time import sleep    
     
def onsignal_term(a,b):    
    print '收到SIGTERM信号'    
     
#这里是绑定信号处理函数,将SIGTERM绑定在函数onsignal_term上面    
signal.signal(signal.SIGTERM,onsignal_term)    
     
def onsignal_usr1(a,b):    
    print '收到SIGUSR1信号'    
#这里是绑定信号处理函数,将SIGUSR1绑定在函数onsignal_term上面    
signal.signal(signal.SIGUSR1,onsignal_usr1)    
     
while 1:    
    print '我的进程id是',os.getpid()    
    sleep(10)

在另一个终端中执行

import os    
import signal    
     
#发送信号,16175是前面那个绑定信号处理函数的pid,需要自行修改    
os.kill(16175,signal.SIGTERM)    
#发送信号,16175是前面那个绑定信号处理函数的pid,需要自行修改    
os.kill(16175,signal.SIGUSR1)

上述示意了简单的信号功能,可以用来自定义捕捉信号并执行相应的函数。使用信号需要特别注意的地方:如果一个进程收到一个SIGUSR1信号,然后执行信号绑定函数,第二个SIGUSR2信号又来了,第一个信号没有被处理完毕的话,第二个信号就会丢弃。所以,尽量不要在多线程中使用信号。

argparse模块

命令行解析工具,new in 2.7

import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',
                    help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',
                    const=sum, default=max,
                    help='sum the integers (default: find the max)')

args = parser.parse_args()
print args.accumulate(args.integers)

首先,创建一个 ArgumentParser
对象,
parser = argparse.ArgumentParser(description='Process some integers.')
然后添加参数,实现参数添加是通过调用函数add_argument,该函数告诉ArgumentParser对象将新添加的参数保存为attributes,最后parse_args()会返回该对象且该对象新增了对应添加的属性。

主要method分析

ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])
  • name or flags - Either a name or a list of option strings, e.g. foo
    or -f, --foo
  • action - The basic type of action to be taken when this argument is encountered at the command line.
  • nargs - The number of command-line arguments that should be consumed.
  • const - A constant value required by some action and nargs selections.
  • default - The value produced if the argument is absent from the command line.
  • type - The type to which the command-line argument should be converted.
    choices - A container of the allowable values for the argument.
  • required - Whether or not the command-line option may be omitted (optionals only).
  • help - A brief description of what the argument does.
  • metavar - A name for the argument in usage messages.
  • dest - The name of the attribute to be added to the object returned by parse_args()
    .

详细用法查阅

nargs

parser.add_argument('--foo', nargs=2),最为简单用法,表示--foo 需要两个参数,如果传递的参数不对,则会引发error

parser.add_argument('--foo', nargs='?', const='c', default='d'),从命令行传递至多一个参数,如果没有则用default指定的。‘?’相对更灵活,当命令行没有参数输入时程序不会出错,使用默认的。而上面指定个数后输入参数不对程序直接挂掉。

nargs='*' 不直接指定个数,传入的参数表示成一个列表。

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', nargs='*')
>>> parser.add_argument('--bar', nargs='*')
>>> parser.add_argument('baz', nargs='*')
>>> parser.parse_args('a b --foo x y --bar 1 2'.split())
Namespace(bar=['1', '2'], baz=['a', 'b'], foo=['x', 'y'])

nargs = '+' 很像'*',但最低要求一个参数,当没有参数时报错。而‘’可以没有参数。
总结来说nargs常规用法就是硬性指定参数个数,‘?’,‘
’,‘+’则提供了更多的灵活性,也是程序中较常用的。

action

大部分action完成的动作就是为对象添加该属性,默认的动作是‘store’,parser.parse_args()返回的对象具有新增属性,如

args = parser.parse_args()
print args.accumulate(args.integers)

'store_const' --This stores the value specified by the const keyword argument.
'store_true' and 'store_false' 类似于上面的’store_const‘,只是存储的是True和False。
'append',允许多次指定一个参数,返回该参数列表集合。

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='append')
>>> parser.parse_args('--foo 1 --foo 2'.split())
Namespace(foo=['1', '2'])
type

‘type’,默认是以字符串读入命令行的参数,但实际中还会要有int 、float等类型的数据输入,这时可以通过type指定。

>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('foo', type=int)
_StoreAction(option_strings=[], dest='foo', nargs=None, const=None, default=None, type=<type 'int'>, choices=None, help=None, metavar=None)
>>> parser.add_argument('bar', type=file)
_StoreAction(option_strings=[], dest='bar', nargs=None, const=None, default=None, type=<type 'file'>, choices=None, help=None, metavar=None)
>>> ar = parser.parse_args('2 myfile.txt'.split())
>>> ar.foo
2
>>> ar.bar
<open file 'myfile.txt', mode 'r' at 0x7f352c089300>
>>> ar.bar.read()  //返回的是字符串
'myfile.txt\n'

上述程序中有以下两点注意:一是parser.parse_args()函数返回的对象具有了新增加的属性,二是可以进行整个文件的输入操作,只要通过获取属性的方法就能获取到文件句柄,十分方便。

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('bar', type=argparse.FileType('w'))
>>> parser.parse_args(['out.txt'])
Namespace(bar=<open file 'out.txt', mode 'w' at 0x...>)

通过 type=argparse.FileType('w') 完成文件打开方式,默认的type=file为只读模式。
type还能是函数名,实现传递函数的功能。

choices
>>> parser.add_argument('move', choices=['rock', 'paper', 'scissors'])
>>> parser.parse_args(['rock'])
Namespace(move='rock')

给参数限定了范围,如上述中参数 move只能是三者之一。

required
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', required=True)
>>> parser.parse_args(['--foo', 'BAR'])
Namespace(foo='BAR')
>>> parser.parse_args([])
usage: argparse.py [-h] [--foo FOO]
argparse.py: error: option --foo is required

表示必选参数。

help

指定 -h时显示帮助信息,以下两种方式可以显示帮助信息
parser.print_help()
parser.parse_args(['-h'])

metavar
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', metavar='YYY')
>>> parser.add_argument('bar', metavar='XXX')
>>> parser.parse_args('X --foo Y'.split())
Namespace(bar='X', foo='Y')
>>> parser.print_help()
usage:  [-h] [--foo YYY] XXX

positional arguments:
 XXX

optional arguments:
 -h, --help  show this help message and exit
 --foo YYY
dest

该参数决定了parser.parse_args()函数返回后增加的属性名,若不指定则一般用第一个参数指定。

struct 模块

参考学习来源
实现python值和结构体之间的转换,当网络中传递字符串时很方便,但结构体由于包含int、char等不同类型,需要一种机制将其打包成二进制流的字符串。
struct模块中最主要的三个函数式pack()、unpack()、calcsize()。
pack(fmt, v1, v2, ...) ------ 根据所给的fmt描述的格式将值v1,v2,...转换为一个字符串。
unpack(fmt, bytes) ------ 根据所给的fmt描述的格式将bytes反向解析出来,返回一个元组。
calcsize(fmt) ------ 根据所给的fmt描述的格式返回该结构的大小。

 struct header

      {

          unsigned short  usType;

          char[4]               acTag;

          unsigned int      uiVersion;

          unsigned int      uiLength;

      };

 # 在C语言对将该结构体封装到一块缓存中是很简单的,可以使用memcpy()实现。在Python中,使用struct就需要这样:

str = struct.pack('B4sII', 0x04, 'aaaa', 0x01, 0x0e)

 # 'B4sII'  ------   有一个unsigned short、char[4], 2个unsigned int。其中s之前的数字说明了字符串的大小 。
type, tag, version, length = struct.unpack('B4sll', str)

常用的格式有以下:


image.png

除了上述直接调用struct模块中的函数,struct封装了一个类,class struct.Struct(format),该类中同样封装了pack,unpack等method,但是封装格式在struct.Struct(format)中format参数指定,不用再method中指定。该类的效率更高因为只需要编译一次。

Creating a Struct object once and calling its methods is more efficient than calling the struct
functions with the same format since the format string only needs to be compiled once.

import struct
import binascii
values = (1, 'abc', 2.7)
s = struct.Struct('I3sf')
packed_data = s.pack(*values)
unpacked_data = s.unpack(packed_data)
print 'Original values:', values
print 'Format string :', s.format
print 'Uses :', s.size, 'bytes'
print 'Packed Value :', binascii.hexlify(packed_data)
print 'Unpacked Type :', type(unpacked_data), ' Value:', unpacked_data

输出:
Original values: (1, 'abc', 2.7)
Format string : I3sf
Uses : 12 bytes
Packed Value : 0100000061626300cdcc2c40
Unpacked Type : <type 'tuple'> Value: (1, 'abc', 2.700000047683716)

扩展:计算机存储格式

打包的后的字节顺序默认上是由操作系统的决定的,当然struct模块也提供了自定义字节顺序的功能,可以指定大端存储、小端存储等特定的字节顺序,对于底层通信的字节顺序是十分重要的,不同的字节顺序和存储方式也会导致字节大小的不同。在format字符串前面加上特定的符号即可以表示不同的字节顺序存储方式,例如采用小端存储 s = struct.Struct(‘<I3sf’)就可以了。

image.png

若没有指定,默认为@,即本地默认字节序,不同系统不一样,可以通过sys.byteorder查看。网络字节序是大端格式,用!以防自己记不起来大端还是小端。

fcntl 模块

根据文件描述符对文件或IO进行控制,
fcntl.flock(f,fcntl.LOCK_EX)
这样就对文件test加锁了,如果有其他进程对test文件加锁,则不能成功,会被阻塞,但不会退出程序。
解锁:
fcntl.flock(f,fcntl.LOCK_UN)

flock() : flock(f, operation)
operation : 包括:
fcntl.LOCK_UN 解锁
fcntl.LOCK_EX 排他锁
fcntl.LOCK_SH 共享锁
fcntl.LOCK_NB 非阻塞锁
LOCK_SH 共享锁:所有进程没有写访问权限,即使是加锁进程也没有。所有进程有读访问权限。
LOCK_EX 排他锁:除加锁进程外其他进程没有对已加锁文件读写访问权限。
LOCK_NB 非阻塞锁:
如果指定此参数,函数不能获得文件锁就立即返回,否则,函数会等待获得文件锁。LOCK_NB可以同LOCK_SH或LOCK_NB进行按位或(|)运算操作。 fcnt.flock(f,fcntl.LOCK_EX|fcntl.LOCK_NB)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容