wifijammer源碼分析一

處于學習別人代碼風格階段,github參考學習程序
程序開頭會有

#!/usr/bin/python
# -*- coding: utf-8 -*-

一是用來指定腳本語言為 Python,二是用來指定文件編碼為utf-8.

1、Python logging 模塊使用

最好學習資料還是官方文檔

(1)輸出等級

logging是一個實用的輔助工具,可以分等級地打印調試信息或錯誤信息。分為五個等級:

Paste_Image.png

默認是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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

推薦閱讀更多精彩內容