1. 程式人生 > >Python 掃描存活主機

Python 掃描存活主機

ber test 客戶端訪問 get code true UC args 服務器

案例1:簡化除法判斷 案例2:分析apache訪問日誌 案例3:掃描存活主機 案例4:利用多線程實現ssh並發訪問

1 案例1:簡化除法判斷
1.1 問題

編寫mydiv.py腳本,主要要求如下:

提示用戶輸入一個數字作為除數
如果用戶按下Ctrl+C或Ctrl+D則退出程序
如果用戶輸入非數字字符,提示用戶應該輸入數字
如果用戶輸入0,提示用戶0不能作為除數

1.2 方案

使用if語句判斷除數是否合適,需要編寫多條語句。有了異常處理,可以本著先做,錯了再說的邏輯。直接把除法操作放在try語句中執行,根據產生的異常做相應的處理。

另外,Ctrl+C或Ctrl+D只能通過異常捕獲。

異常捕獲的語法如下:

try:
    A
except:
    B
else:
    C
finally:
    D

把可能發生異常的語句放在A裏面執行,如果出現異常則執行B語句,沒有異常則執行C語句。不管是否出現異常都會執行D語句。

捕獲異常時,可以使用多個except語句,每個except語句捕獲一個異常,每個異常給定不同的處理方法。也可以把多個異常放在同一個except語句後面,但是務必註意,多個異常寫在相同的一行,一定要註括號括起來,放在元組中。
1.3 步驟

實現此案例需要按照如下步驟進行。

步驟一:編寫腳本

#!/usr/bin/env python
import  sys
while True:
    try:
        result = 100 / int(raw_input(‘enter a number: ‘))
    except (ValueError, ZeroDivisionError), e:   #將異常原因保存在變量e中
        print "invalid input:", e
        continue
    except  (EOFError, KeyboardInterrupt):
        sys.exit(1)
    break
print  result

步驟二:測試腳本執行

[root@py01 bin]# ./mydiv.py
enter a number: 0
invalid input: integer division or modulo by zero
enter a number: abc
invalid input: invalid literal for int() with base 10: ‘abc‘
enter a number: 3
33

2 案例2:分析apache訪問日誌
2.1 問題

編寫用於分析apache日誌的腳本,主要要求如下:

統計每個客戶端訪問apache服務器的次數
將統計信息通過字典的方式顯示出來
分別統計客戶端是Firefox和MSIE的訪問次數
分別使用函數式編程和面向對象編程的方式實現

2.2 方案

涉及到文本處理時,正則表達式將是一個非常強大的工具。匹配客戶端的IP地址,可以使用正則表達式的元字符,匹配字符串可以直接使用字符的表面含義。

入門級程序員的寫法,使用順序的結構,直接編寫。這種方法雖然可以得出結果,但是代碼難以重用。參考步驟一。

進階的寫法可以采用函數式編程,方便日後再次使用。參考步驟二。

最後,還可以使用OOP的編程方法,先定義一個統計類,該類將正則表達式作為它的數據屬性。再定義一個方法,從指定的文件中搜索正則表達式出現的次數,並將其存入到一個字典中。參考步驟三。
2.3 步驟

實現此案例需要按照如下步驟進行。

步驟一:簡單實現

[root@py01 bin]# vim countweb.py
#!/usr/bin/env python
import re
logfile = ‘/var/log/httpd/access_log‘
cDict = {}
patt_ip = ‘^\d+\.\d+\.\d+\.\d+‘         #定義匹配IP地址的正則表達式
with open(logfile) as f:
    for eachLine in f:
        m = re.search(patt_ip, eachLine)
        if m is not None:
            ipaddr = m.group()
            #如果IP地址已在字典中,將其值加1,否則初始值設置為1
            cDict[ipaddr] = cDict.get(ipaddr, 0) + 1
print cDict

步驟二:使用函數式編程實現

[root@py01 bin]# vim countweb2.py
!/usr/bin/env python
import re
def countPatt(patt, fname):   #定義可以在指定文件中搜索指定字符串的函數
    cDict = {}
    with open(fname) as f:
        for eachLine in f:
            m = re.search(patt, eachLine)
            if m is not None:
                k = m.group()
                cDict[k] = cDict.get(k, 0) + 1
    return cDict
def test():
    logfile = ‘/var/log/httpd/access_log‘
    patt_ip = ‘^\d+\.\d+\.\d+\.\d+‘
    print countPatt(patt_ip, logfile)
    patt_br = ‘Firefox|MSIE‘
    print countPatt(patt_br, logfile)
if __name__ == ‘__main__‘:
    test()

3 案例3:掃描存活主機
3.1 問題

編寫掃描存活主機的腳本,主要要求如下:

調用系統的ping命令進行掃描
掃描教室環境下所有存活的主機
采用多線程的方式編寫
方案

os模塊的system()函數可以調用系統命令,其返回值是系統命令退出碼,也就是如果系統命令成功執行,返回0,如果沒有成功執行,返回非零值。

本例掃描主機,可以調用系統的ping命令,通過退出碼來判斷是否ping通了該主機。如果順序執行,每個ping操作需要消耗數秒鐘,全部的254個地址需要10分鐘以上。而采用多線程,可以實現對這254個地址同時執行ping操作,並發的結果就是將執行時間縮短到了10秒鐘左右。
3.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:編寫腳本

[root@py01 bin]# vim mtping.py
#!/usr/bin/env python
import subprocess
import threading
import sys
def ping(ip):
    result = subprocess.call("ping -c2 %s &> /dev/null" % ip, shell=True)
    if result:
        print "%s:down" % ip
    else:
        print "%s:up" % ip
if __name__ == ‘__main__‘:
    if len(sys.argv) != 2:
        print "Usage: %s subnet" % sys.argv[0]
        sys.exit(1)
    net_list = sys.argv[1].split(‘.‘)
    net = ‘.‘.join(net_list[:-1])
    ips = ("%s.%s" % (net, i) for i in range(1, 255))
    for ip in ips:
        t = threading.Thread(target=ping, args=(ip,))
        t.start()

步驟二:測試腳本執行

[root@py01 bin]# python mtping.py 172.40.51.0

腳本接受命令行參數,只要給定網段就可以實現對該網段中所有ip地址的ping操作。
4 案例4:利用多線程實現ssh並發訪問
4.1 問題

編寫ssh客戶端腳本,主要要求如下:

在文件中取出所有遠程主機IP地址
在shell命令行中接受遠程服務器IP地址文件、遠程服務器密碼以及在遠程主機上執行的命令
通過多線程實現在所有的遠程服務器上並發執行命令
方案

python的paramiko模塊可以實現ssh客戶端的功能,使用起來也比較簡單。但是當服務器非常多的時候,每臺服務器上執行完全相同的簡單操作,也會花費大量的時間。

通過ssh加上多線程,可以實現並發訪問。為了將程序寫的靈活性更強,把要執行的命令以位置參數的方式來提供。
4.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:編寫腳本

[root@py01 bin]# vim remote_comm.py
#!/usr/bin/env python
import paramiko
import os
import sys
import threading
def remote_comm(host, password, comm):
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(host, username=‘root‘, password=password)
    stdin, stdout, stderr = ssh.exec_command(comm)
    out = stdout.read()
    err = stderr.read()
    if out:
        print "[%s:out]: %s" % (host, out),
    if err:
        print "%s:Error: %s", (host, err),
    ssh.close()
if __name__ == ‘__main__‘:
    if len(sys.argv) != 4:
        print "Usage: %s ipfile password ‘comm‘" % sys.argv[0]
        sys.exit(1)
    ipfile = sys.argv[1]
    if not os.path.isfile(ipfile):
        print "No such file: %s" % ipfile
        sys.exit(2)
    password = sys.argv[2]
    comm = sys.argv[3]
    with open(ipfile) as fobj:
        for line in fobj:
            ip = line.strip()
            t = threading.Thread(target=remote_comm, args=(ip, password, comm))
            t.start()

步驟二:測試腳本執行

[root@py01 bin]# python remote_comm.py ipaddr.txt tedu.cn ‘useradd bob‘

腳本接受命令行參數,其中ipaddr.txt是存放所有遠程主機ip地址的文件,文件中每個ip地址占一行。tedu.cn是遠程主機的密碼(所有遠程主機密碼需要是一致的)。最後的命令需要寫在引號中。

該示例執行成功後,會在所有遠程主機上創建一個名為bob的用戶。

Python 掃描存活主機