處于學(xué)習(xí)別人代碼風(fēng)格階段,github參考學(xué)習(xí)程序
程序開頭會有
#!/usr/bin/python
# -*- coding: utf-8 -*-
一是用來指定腳本語言為 Python,二是用來指定文件編碼為utf-8.
1、Python logging 模塊使用
(1)輸出等級
logging是一個實用的輔助工具,可以分等級地打印調(diào)試信息或錯誤信息屯断。分為五個等級:
默認(rèn)是warning等級。設(shè)置等級后只有大于等于該等級的信息會打印出。不指定文件則打印在終端上殖演⊙趺兀可以通過以下方式指定輸出文件和輸出等級:
logging.basicConfig(filename='example.log',level=logging.DEBUG)
也可以在命令行通過 --log=INFO/DEBUG/ERROR等
(2)格式化顯示
可以根據(jù)自己的需要改變顯示信息的格式,如:
logging.warning('%s before you %s', 'Look', 'leap!')
import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.debug('This message should appear on the console')
logging.info('So should this')
logging.warning('And this, too')
打印出:
DEBUG:This message should appear on the console
INFO:So should this
WARNING:And this, too
即可以通過basicConfig改變輸出格式趴久,默認(rèn)為
WARNING:root:Look before you leap!
關(guān)于時間
import logging
logging.basicConfig(format='%(asctime)s %(message)s')
logging.warning('is when this event was logged.')
打印出:
2017-04-29 19:47:17,128 is when this event happened
也可以改變默認(rèn)的時間顯示格式(some problem):
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
(3)深入學(xué)習(xí)
https://docs.python.org/2/howto/logging-cookbook.html#logging-cookbook
程序示例:
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='myapp.log',
filemode='w')
#################################################################################################
#定義一個StreamHandler丸相,將INFO級別或更高的日志信息打印到標(biāo)準(zhǔn)錯誤,并將其添加到當(dāng)前的日志處理對象#
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
#################################################################################################
logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')
當(dāng)沒有指定filename時彼棍,默認(rèn)為標(biāo)準(zhǔn)錯誤輸出灭忠,如上程序中的StreamHandler。
2座硕、scapy工具使用
scapy是一個強大的第三方庫弛作,用于網(wǎng)絡(luò)嗅探。能夠偽造或者解碼大量的網(wǎng)絡(luò)協(xié)議數(shù)據(jù)包华匾,能夠發(fā)送缆蝉、捕捉、匹配請求和回復(fù)包等等瘦真。它可以很容易地處理一些典型操作,比如端口掃描黍瞧,tracerouting诸尽,探測,單元 測試印颤,攻擊或網(wǎng)絡(luò)發(fā)現(xiàn)(可替代hping您机,NMAP,arpspoof年局,ARP-SK际看,arping,tcpdump矢否,tethereal仲闽,P0F等)。 最重要的他還有很多更優(yōu)秀的特性——發(fā)送無效數(shù)據(jù)幀僵朗、注入修改的802.11數(shù)據(jù)幀赖欣、在WEP上解碼加密通道(VOIP)、ARP緩存攻擊(VLAN) 等验庙,這也是其他工具無法處理完成的顶吮。
有以下兩種使用方式:
執(zhí)行sudo scapy命令進(jìn)入交互式數(shù)據(jù)包處理,或在Python代碼中使用from scapy.all import *引入scapy
3粪薛、threading模塊實現(xiàn)多線程
threading對thread(多線程底層支持模塊悴了,一般不建議使用)進(jìn)行了封裝,將一些線程的操作對象化
參考 http://www.cszhi.com/20130528/python-threading.html
import threading
def thread_fun(num):
for n in range(0, int(num)):
print " I come from %s, num: %s" %( threading.currentThread().getName(), n)
def main(thread_num):
thread_list = list();
# 先創(chuàng)建線程對象
for i in range(0, thread_num):
thread_name = "thread_%s" %i
thread_list.append(threading.Thread(target = thread_fun, name = thread_name, args = (20,)))
# 啟動所有線程
for thread in thread_list:
thread.start()
# 主線程中等待所有子線程退出
for thread in thread_list:
thread.join()
if __name__ == "__main__":
main(3)
列表的廣義化,列表可以是函數(shù)湃交、類的集合熟空。可以理解為存放的是地址巡揍。通過threading.Thread函數(shù)創(chuàng)建一個線程痛阻,指定target-回調(diào)函數(shù),線程名以及參數(shù)等腮敌。
thread.join()函數(shù)會依次檢測線程池中的線程是否結(jié)束阱当,沒有結(jié)束就阻塞直到線程結(jié)束,結(jié)束后會跳轉(zhuǎn)執(zhí)行下一個線程的join函數(shù)糜工。Python的join函數(shù)還可以設(shè)置超時時間弊添,Thread.join([timeout])。
上述是通過自定義創(chuàng)建函數(shù)捌木,并通過Thread運行油坝,也可以繼承Thread類進(jìn)行簡化編程。
import threading
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self);
def run(self):
print "I am %s" %self.name
if __name__ == "__main__":
for thread in range(0, 5):
t = MyThread()
t.start()
通過自定義run函數(shù)重寫Thread中的run函數(shù)刨裆。
擴展:
(1)setdaemon函數(shù)
Python中得thread的一些機制和C/C++不同:在C/C++中澈圈,主線程結(jié)束后,其子線程會默認(rèn)被主線程kill掉帆啃。而在python中瞬女,主線程結(jié)束后,會默認(rèn)等待子線程結(jié)束后努潘,主線程才退出诽偷。
setDaemon:主線程A啟動了子線程B,調(diào)用b.setDaemaon(True)疯坤,則主線程結(jié)束時报慕,會把子線程B也殺死,與C/C++中得默認(rèn)效果是一樣的压怠。
#! /usr/bin/env python
import threading
import time
class myThread(threading.Thread):
def __init__(self, threadname):
threading.Thread.__init__(self, name=threadname)
self.st = 2
def run(self):
time.sleep(self.st)
print self.getName()
def setSt(self, t):
self.st = t
def fun1():
t1.start()
print "fun1 done"
def fun2():
t2.start()
print "fun2 done"
t1=myThread("t1")
t2=myThread("t2")
t2.setSt(10);
# t2.setDaemon(True)
fun1()
fun2()
print "now u will see me"
當(dāng) t2.setDaemon(True)沒有生效時眠冈,打印出
fun1 done
fun2 done
now u will see me
t1
t2
生效后,打印出
fun1 done
fun2 done
now u will see me
t1
t2.setDaemon(True)表示主進(jìn)程結(jié)束后立即結(jié)束子進(jìn)程菌瘫,不管子進(jìn)程有沒有運行完成洋闽。
(2)互斥鎖
多個線程訪問同一資源,由于先后順序不確定突梦,產(chǎn)生“線程不安全”诫舅,引入互斥鎖,使無序變有序宫患。
import threading
import time
counter = 0
mutex = threading.Lock()
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global counter, mutex
time.sleep(1);
if mutex.acquire():
counter += 1
print "I am %s, set counter:%s" % (self.name, counter)
mutex.release()
if __name__ == "__main__":
for i in range(0, 100):
my_thread = MyThread()
my_thread.start()
當(dāng)一個線程調(diào)用Lock對象的acquire()方法獲得鎖時刊懈,這把鎖就進(jìn)入“l(fā)ocked”狀態(tài)。因為每次只有一個線程1可以獲得鎖,所以如果此時另一個線程2試圖獲得這個鎖虚汛,該線程2就會變?yōu)椤癰lock“同步阻塞狀態(tài)匾浪。直到擁有鎖的線程1調(diào)用鎖的release()方法釋放鎖之后,該鎖進(jìn)入“unlocked”狀態(tài)卷哩。線程調(diào)度程序從處于同步阻塞狀態(tài)的線程中選擇一個來獲得鎖蛋辈,并使得該線程進(jìn)入運行(running)狀態(tài)。
(3)避免死鎖
(4)進(jìn)程間通信
(5)管道pipe
4将谊、subprocess 模塊
官網(wǎng)參考資料
subprocess允許開啟一個新的進(jìn)程冷溶,并與之通信。
subprocess用來代替以下模塊:
- os.system
- os.spawn*
- os.popen*
- popen2.*
- commands.*
(1)subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
運行參數(shù)中的命令尊浓,并返回 returncode,如:
subprocess.call(['ls','-al'])
在官方文檔中有以下注意
Note :Do not use stdout=PIPE or stderr=PIPE with this function as that can deadlock based on the child process output volume. Use Popen
with the communicate() method when you need pipes.
值得注意shell=False這個參數(shù)逞频,根據(jù)官網(wǎng)shell=False比shell=True更安全,假設(shè)運行以下
cmd = "cat test.txt; rm test.txt"
subprocess.call(cmd, shell=True)
shell=True參數(shù)會讓subprocess.call接受字符串類型的變量作為命令栋齿,并調(diào)用shell去執(zhí)行這個字符串苗胀,第一個測試中的分號被認(rèn)為是shell命令中的分隔符,執(zhí)行了cat和rm兩個命令瓦堵。
當(dāng)shell=False時基协,subprocess.call只接受數(shù)組變量作為命令,并將數(shù)組的第一個元素作為命令菇用,剩下的全部作為該命令的參數(shù)澜驮,因此第二個測試只執(zhí)行了cat命令,并試著打開了作為參數(shù)的”text.txt;”刨疼,”rm” , “text.txt”三個文件。
(2)subprocess.check_call (*popenargs , **kwargs )
執(zhí)行上面的call命令鹅龄,并檢查返回值揩慕,如果子進(jìn)程返回非0,則會拋出CalledProcessError異常扮休,這個異常會有個returncode
屬性迎卤,記錄子進(jìn)程的返回值。
(2)subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)
和上個函數(shù)類似玷坠,主要不同在于將所有輸出保存為字符串蜗搔,而不直接打印到標(biāo)準(zhǔn)輸出。
>>> import subprocess
>>> str = subprocess.check_output(['echo','hello world'])
>>> str
'hello world\n'
>>>
(3) class subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)
是該模塊中最為重要的方法之一八堡,創(chuàng)建一個新進(jìn)程樟凄,類似于unix系統(tǒng)下的 os.execvp()
,windows下的 CreateProcess() 兄渺。
>>> import shlex, subprocess
>>> command_line = raw_input()
/bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'"
>>> args = shlex.split(command_line)
>>> print args
['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"]
>>> p = subprocess.Popen(args) # Success!
shelex是一個簡單的詞典分析模塊 ,shlex.split()
可以被用于序列化復(fù)雜的命令參數(shù)缝龄,比如:
>>> shlex.split('ls ps top grep pkill')
['ls', 'ps', 'top', 'grep', 'pkill']
args參數(shù):
可以是一個字符串,可以是一個包含程序參數(shù)的列表。要執(zhí)行的程序一般就是這個列表的第一項叔壤,或者是字符串本身瞎饲。
subprocess.Popen(["cat","test.txt"])
subprocess.Popen("cat test.txt")
這兩個之中,后者將不會工作炼绘。因為如果是一個字符串的話嗅战,必須是程序的路徑才可以。
但是下面的可以工作 subprocess.Popen("cat test.txt", shell=True)
這是因為它相當(dāng)于 subprocess.Popen(["/bin/sh", "-c", "cat test.txt"])
在*nix下俺亮,當(dāng)shell=False(默認(rèn))時驮捍,Popen使用os.execvp()來執(zhí)行子程序。args一般要是一個【列表】铅辞。如果args是個字符串的
話厌漂,會被當(dāng)做是可執(zhí)行文件的路徑,這樣就不能傳入任何參數(shù)了斟珊。
executable參數(shù) :
很少用到苇倡,用來指定要執(zhí)行的程序,一般程序可以用args參數(shù)指定囤踩。
preexec_fn參數(shù):
如果把preexec_fn設(shè)置為一個可調(diào)用的對象(比如函數(shù))旨椒,就會在子進(jìn)程被執(zhí)行前被調(diào)用。(僅限*nix)
close_fds參數(shù):
如果把close_fds設(shè)置成True堵漱,*nix下會在開子進(jìn)程前把除了0综慎、1、2以外的文件描述符都先關(guān)閉勤庐。在 Windows下也不會繼承其他文件描述符示惊。
shell參數(shù):
如果把shell設(shè)置成True,指定的命令會在shell里解釋執(zhí)行愉镰。
cwd參數(shù):
如果cwd不是None米罚,則會把cwd做為子程序的當(dāng)前目錄。注意丈探,并不會把該目錄做為可執(zhí)行文件的搜索目錄录择,所以不要把程序文件所在
目錄設(shè)置為cwd 。
env參數(shù):
如果env不是None碗降,則子程序的環(huán)境變量由env的值來設(shè)置隘竭,而不是默認(rèn)那樣繼承父進(jìn)程的環(huán)境變量。注意讼渊,即使你只在env里定義了
某一個環(huán)境變量的值动看,也會阻止子程序得到其他的父進(jìn)程的環(huán)境變量
后面幾個很少用到。
Popen類的method
Popen.poll()
Check if child process has terminated. Set and return returncode attribute.
Popen.wait()
Wait for child process to terminate. Set and return returncode attribute.
Popen.communicate(input=None)
Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child.
Popen.send_signal(signal)
Popen.terminate()
停止一個子進(jìn)程爪幻,在linux下發(fā)送SIGTERM信號給子進(jìn)程
Popen.kill()
殺死一個子進(jìn)程弧圆,在linux下發(fā)送SIGKILL給子進(jìn)程赋兵。
常用的一些屬性
- Popen.returncode
- Popen.pid
- Popen.stderr
- Popen.stdout
- Popen.stdin
對于Popen.stdin,如果stdin是PIPE搔预,則這個屬性返回的是為子進(jìn)程提供輸入的文件對象霹期。
同理,If the stdout argument was PIPE
, Popen.stdout is a file object that provides output from the child process. Otherwise, it is None
示例:
output= dmesg | grep hda
等價于
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]
注意以下幾點:
communicate函數(shù)返回一個元祖 (stdoutdata, stderrdata)
當(dāng)Popen函數(shù)中stdout=PIPE時拯田,表示輸出到一個管道中历造,要獲取該管道,Popen.stdout會返回該句柄船庇,可以通過讀文件方法讀出該管道中數(shù)據(jù)吭产。
pipe = os.popen("cmd", 'r', bufsize)
==>
pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout