處于學習別人代碼風格階段,github參考學習程序
程序開頭會有
#!/usr/bin/python
# -*- coding: utf-8 -*-
一是用來指定腳本語言為 Python,二是用來指定文件編碼為utf-8.
1、Python logging 模塊使用
(1)輸出等級
logging是一個實用的輔助工具,可以分等級地打印調試信息或錯誤信息。分為五個等級:
默認是warning等級。設置等級后只有大于等于該等級的信息會打印出。不指定文件則打印在終端上。可以通過以下方式指定輸出文件和輸出等級:
logging.basicConfig(filename='example.log',level=logging.DEBUG)
也可以在命令行通過 --log=INFO/DEBUG/ERROR等
(2)格式化顯示
可以根據自己的需要改變顯示信息的格式,如:
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改變輸出格式,默認為
WARNING:root:Look before you leap!
關于時間
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
也可以改變默認的時間顯示格式(some problem):
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
(3)深入學習
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級別或更高的日志信息打印到標準錯誤,并將其添加到當前的日志處理對象#
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')
當沒有指定filename時,默認為標準錯誤輸出,如上程序中的StreamHandler。
2、scapy工具使用
scapy是一個強大的第三方庫,用于網絡嗅探。能夠偽造或者解碼大量的網絡協議數據包,能夠發送、捕捉、匹配請求和回復包等等。它可以很容易地處理一些典型操作,比如端口掃描,tracerouting,探測,單元 測試,攻擊或網絡發現(可替代hping,NMAP,arpspoof,ARP-SK,arping,tcpdump,tethereal,P0F等)。 最重要的他還有很多更優秀的特性——發送無效數據幀、注入修改的802.11數據幀、在WEP上解碼加密通道(VOIP)、ARP緩存攻擊(VLAN) 等,這也是其他工具無法處理完成的。
有以下兩種使用方式:
執行sudo scapy命令進入交互式數據包處理,或在Python代碼中使用from scapy.all import *引入scapy
3、threading模塊實現多線程
threading對thread(多線程底層支持模塊,一般不建議使用)進行了封裝,將一些線程的操作對象化
參考 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();
# 先創建線程對象
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)
列表的廣義化,列表可以是函數、類的集合。可以理解為存放的是地址。通過threading.Thread函數創建一個線程,指定target-回調函數,線程名以及參數等。
thread.join()函數會依次檢測線程池中的線程是否結束,沒有結束就阻塞直到線程結束,結束后會跳轉執行下一個線程的join函數。Python的join函數還可以設置超時時間,Thread.join([timeout])。
上述是通過自定義創建函數,并通過Thread運行,也可以繼承Thread類進行簡化編程。
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函數重寫Thread中的run函數。
擴展:
(1)setdaemon函數
Python中得thread的一些機制和C/C++不同:在C/C++中,主線程結束后,其子線程會默認被主線程kill掉。而在python中,主線程結束后,會默認等待子線程結束后,主線程才退出。
setDaemon:主線程A啟動了子線程B,調用b.setDaemaon(True),則主線程結束時,會把子線程B也殺死,與C/C++中得默認效果是一樣的。
#! /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"
當 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)表示主進程結束后立即結束子進程,不管子進程有沒有運行完成。
(2)互斥鎖
多個線程訪問同一資源,由于先后順序不確定,產生“線程不安全”,引入互斥鎖,使無序變有序。
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()
當一個線程調用Lock對象的acquire()方法獲得鎖時,這把鎖就進入“locked”狀態。因為每次只有一個線程1可以獲得鎖,所以如果此時另一個線程2試圖獲得這個鎖,該線程2就會變為“block“同步阻塞狀態。直到擁有鎖的線程1調用鎖的release()方法釋放鎖之后,該鎖進入“unlocked”狀態。線程調度程序從處于同步阻塞狀態的線程中選擇一個來獲得鎖,并使得該線程進入運行(running)狀態。
(3)避免死鎖
(4)進程間通信
(5)管道pipe
4、subprocess 模塊
官網參考資料
subprocess允許開啟一個新的進程,并與之通信。
subprocess用來代替以下模塊:
- os.system
- os.spawn*
- os.popen*
- popen2.*
- commands.*
(1)subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
運行參數中的命令,并返回 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這個參數,根據官網shell=False比shell=True更安全,假設運行以下
cmd = "cat test.txt; rm test.txt"
subprocess.call(cmd, shell=True)
shell=True參數會讓subprocess.call接受字符串類型的變量作為命令,并調用shell去執行這個字符串,第一個測試中的分號被認為是shell命令中的分隔符,執行了cat和rm兩個命令。
當shell=False時,subprocess.call只接受數組變量作為命令,并將數組的第一個元素作為命令,剩下的全部作為該命令的參數,因此第二個測試只執行了cat命令,并試著打開了作為參數的”text.txt;”,”rm” , “text.txt”三個文件。
(2)subprocess.check_call (*popenargs , **kwargs )
執行上面的call命令,并檢查返回值,如果子進程返回非0,則會拋出CalledProcessError異常,這個異常會有個returncode
屬性,記錄子進程的返回值。
(2)subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)
和上個函數類似,主要不同在于將所有輸出保存為字符串,而不直接打印到標準輸出。
>>> 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)
是該模塊中最為重要的方法之一,創建一個新進程,類似于unix系統下的 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()
可以被用于序列化復雜的命令參數,比如:
>>> shlex.split('ls ps top grep pkill')
['ls', 'ps', 'top', 'grep', 'pkill']
args參數:
可以是一個字符串,可以是一個包含程序參數的列表。要執行的程序一般就是這個列表的第一項,或者是字符串本身。
subprocess.Popen(["cat","test.txt"])
subprocess.Popen("cat test.txt")
這兩個之中,后者將不會工作。因為如果是一個字符串的話,必須是程序的路徑才可以。
但是下面的可以工作 subprocess.Popen("cat test.txt", shell=True)
這是因為它相當于 subprocess.Popen(["/bin/sh", "-c", "cat test.txt"])
在*nix下,當shell=False(默認)時,Popen使用os.execvp()來執行子程序。args一般要是一個【列表】。如果args是個字符串的
話,會被當做是可執行文件的路徑,這樣就不能傳入任何參數了。
executable參數 :
很少用到,用來指定要執行的程序,一般程序可以用args參數指定。
preexec_fn參數:
如果把preexec_fn設置為一個可調用的對象(比如函數),就會在子進程被執行前被調用。(僅限*nix)
close_fds參數:
如果把close_fds設置成True,*nix下會在開子進程前把除了0、1、2以外的文件描述符都先關閉。在 Windows下也不會繼承其他文件描述符。
shell參數:
如果把shell設置成True,指定的命令會在shell里解釋執行。
cwd參數:
如果cwd不是None,則會把cwd做為子程序的當前目錄。注意,并不會把該目錄做為可執行文件的搜索目錄,所以不要把程序文件所在
目錄設置為cwd 。
env參數:
如果env不是None,則子程序的環境變量由env的值來設置,而不是默認那樣繼承父進程的環境變量。注意,即使你只在env里定義了
某一個環境變量的值,也會阻止子程序得到其他的父進程的環境變量
后面幾個很少用到。
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()
停止一個子進程,在linux下發送SIGTERM信號給子進程
Popen.kill()
殺死一個子進程,在linux下發送SIGKILL給子進程。
常用的一些屬性
- Popen.returncode
- Popen.pid
- Popen.stderr
- Popen.stdout
- Popen.stdin
對于Popen.stdin,如果stdin是PIPE,則這個屬性返回的是為子進程提供輸入的文件對象。
同理,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函數返回一個元祖 (stdoutdata, stderrdata)
當Popen函數中stdout=PIPE時,表示輸出到一個管道中,要獲取該管道,Popen.stdout會返回該句柄,可以通過讀文件方法讀出該管道中數據。
pipe = os.popen("cmd", 'r', bufsize)
==>
pipe = Popen("cmd", shell=True, bufsize=bufsize, stdout=PIPE).stdout