主要詳細學習代碼中以下幾個模塊
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)
常用的格式有以下:
除了上述直接調用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’)就可以了。
若沒有指定,默認為@,即本地默認字節序,不同系統不一樣,可以通過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)