1. 程式人生 > >Python開發基礎----異常處理、socket套接字基礎1

Python開發基礎----異常處理、socket套接字基礎1

括號 return 提示 傳輸層 init and prot back vision

異常處理

錯誤

程序裏的錯誤一般分為兩種:

  1、語法錯誤,這種錯誤,根本過不了python解釋器的語法檢測,必須在程序執行前就改正

  2、邏輯錯誤,人為造成的錯誤,如數據類型錯誤、調用方法錯誤等,這些解釋器是不會進行檢測的,只有在執行的過程中才能拋出的錯誤

異常

異常是python解釋器在運行程序的過程中遇到錯誤所拋出的信息,如:

技術分享

Python異常種類:

常用異常:

技術分享
 1 AttributeError     試圖訪問一個對象沒有的樹形,比如foo.x,但是foo沒有屬性x
 2 IOError     輸入/輸出異常;基本上是無法打開文件
 3 ImportError     無法引入模塊或包;基本上是路徑問題或名稱錯誤
 4 IndentationError     語法錯誤(的子類) ;代碼沒有正確對齊
 5 IndexError     下標索引超出序列邊界,比如當x只有三個元素,卻試圖訪問x[5]
 6 KeyError     試圖訪問字典裏不存在的鍵
 7 KeyboardInterrupt     Ctrl+C被按下
 8 NameError     使用一個還未被賦予對象的變量
 9 SyntaxError     Python代碼非法,代碼不能編譯(個人認為這是語法錯誤,寫錯了)
10 TypeError     傳入對象類型與要求的不符合
11 UnboundLocalError     試圖訪問一個還未被設置的局部變量,基本上是由於另有一個同名的全局變量,導致你以為正在訪問它
12 ValueError     傳入一個調用者不期望的值,即使值的類型是正確的
技術分享

其他異常:

技術分享 技術分享
 1 ArithmeticError
 2 AssertionError
 3 AttributeError
 4 BaseException
 5 BufferError
 6 BytesWarning
 7 DeprecationWarning
 8 EnvironmentError
 9 EOFError
10 Exception
11 FloatingPointError
12 FutureWarning
13 GeneratorExit
14 ImportError
15 ImportWarning
16 IndentationError
17 IndexError
18 IOError
19 KeyboardInterrupt
20 KeyError
21 LookupError
22 MemoryError
23 NameError
24 NotImplementedError
25 OSError
26 OverflowError
27 PendingDeprecationWarning
28 ReferenceError
29 RuntimeError
30 RuntimeWarning
31 StandardError
32 StopIteration
33 SyntaxError
34 SyntaxWarning
35 SystemError
36 SystemExit
37 TabError
38 TypeError
39 UnboundLocalError
40 UnicodeDecodeError
41 UnicodeEncodeError
42 UnicodeError
43 UnicodeTranslateError
44 UnicodeWarning
45 UserWarning
46 ValueError
47 Warning
48 ZeroDivisionError
技術分享

異常處理

默認情況下(非程序員使用raise觸發的異常),當執行的程序遇到錯誤拋出異常後會終止程序的運行,在錯誤點中斷,後面的代碼不會繼續執行。

異常處理是指通過指定的代碼進行異常捕捉,當捕捉到指定的異常類則進入特定的邏輯繼續執行,使得程序不會在錯誤點中斷運行,一般用來捕捉程序無法控制的異常錯誤(如客戶端異常中斷與服務器端的連接導致服務器端崩潰)。

if判斷式異常處理

通過邏輯判斷進行控制,想想曾經input+if的方式進行輸入檢測、防止語法錯誤的過程,但是這類if判斷式與原來的邏輯並無關系,所以會造成代碼可讀性差

try...except...異常處理

python定制的一個異常處理類,語法如下:

1 try:
2     被檢測的代碼塊
3 except 異常類型:
4     try中一旦檢測到異常,如果這個異常和except標記的異常一樣,就執行這個位置的邏輯

示例1:叠代器StopIteration異常處理

準備文件a.txt,只有五行內容

1111111
222222222222
33333333
4444
555555555

異常拋出:由於叠代器f沒有那麽多內容,所以第六個__next__會拋出StopIteration異常提示

技術分享
1 f=open(‘a.txt‘,‘r‘)
2 print(f.__next__())
3 print(f.__next__())
4 print(f.__next__())
5 print(f.__next__())
6 print(f.__next__())
7 print(f.__next__())
8 print(f.__next__())
9 print(f.__next__())
技術分享

異常處理:當碰到第六個__next__拋出異常後,except比較異常,如果一樣,那麽關閉文件對象

技術分享
 1 f=open(‘a.txt‘,‘r‘)
 2 try:
 3     print(f.__next__())
 4     print(f.__next__())
 5     print(f.__next__())
 6     print(f.__next__())
 7     print(f.__next__())
 8     print(f.__next__())
 9     print(f.__next__())
10     print(f.__next__())
11 except StopIteration:  #只能夠捕捉處理指定的StopIteration異常,如果是其他的異常則無法處理,依然會拋出錯誤
12     f.close()
技術分享

示例2:多分支異常處理,代碼段中可能會出現多個異常類,而一個except只能指定一個異常,所以可以用多分支結構

技術分享
 1 s=‘asdf‘
 2 l=[‘a‘]
 3 d={‘name‘:‘bob‘}
 4 try:
 5     # int(s)    #ValueError
 6     # l[2]      #IndexError
 7     d[‘age‘]    #KeyError
 8 except IndexError as e:  #as e表示將捕獲的IndexError錯誤信息的異常值賦值給e
 9     print(e)
10 except KeyError as e:
11     print(e)
12 except ValueError as e:
13     print(e)
技術分享

示例3:萬能異常,Exception,他可以捕獲任意異常

技術分享
1 s=‘asdf‘
2 l=[‘a‘]
3 d={‘name‘:‘bob‘}
4 try:
5     int(s)    #ValueError
6     l[2]      #IndexError
7     d[‘age‘]    #KeyError
8 except Exception as e:
9     print(e)
技術分享

註意:如果需求為所有的異常統一一段邏輯處理,那麽使用萬能異常,如果針對不同的異常有不同的處理邏輯,那麽使用多分支結構,多分枝結構的最後可以跟一個萬能異常處理分支

示例4:異常的其他選項

技術分享
 1 s=‘asdf‘
 2 l=[‘a‘]
 3 d={‘name‘:‘bob‘}
 4 try:
 5     int(s)    #ValueError
 6     l[2]      #IndexError
 7     d[‘age‘]    #KeyError
 8 except Exception as e:
 9     print(e)
10 else:
11     print(‘try內代碼塊沒有異常則執行我‘)
12 finally:
13     print(‘無論異常與否,都會執行該模塊,通常是進行清理工作,如關閉文件、刪除對象‘) 
技術分享

示例5:主動觸發異常,人為產生一個異常

技術分享
1 try:
2     raise TypeError(‘類型錯誤‘)    #類型錯誤是所觸發的異常的值
3 except Exception as e:
4     print(e)
5 
6 輸出結果:
7 類型錯誤
技術分享

示例6:自定義異常處理類

技術分享
1 class DefaultException(BaseException):
2     def __init__(self,msg):
3         self.msg=msg
4     def __str__(self):  #定義類本身的返回值
5         return self.msg
6 try:
7     raise DefaultException(‘類型錯誤‘)
8 except DefaultException as e:
9     print(e)    #DefaultException的返回值
技術分享

示例7:斷言,類似於if判斷,不過斷言是絕對真,如果不是真就不會往下執行

1 a=1
2 b=2
3 assert a<b
4 print(a+b)    #輸出結果3
5 assert a>b    #輸出結果:AssertionError異常錯誤
6 print(b-a)    #沒執行

示例8:try和if的比較,如果是if,需要每一個input都要做一次判斷,而try可以對所有的input做處理

技術分享
1 try:
2     num1=input(‘>>: ‘) 
3     int(num1) #正統程序放到了這裏,其余的都屬於異常處理範疇
4     num2=input(‘>>: ‘) 
5     int(num2)
6     num3=input(‘>>: ‘) 
7     int(num3)
8 except ValueError as e:
9     print(e)
技術分享

使用try..except的方式(但是也別忘了if)

1:把錯誤處理和真正的工作分開來

2:代碼更易組織,更清晰,復雜的工作任務更容易實現;

3:毫無疑問,更安全了,不至於由於一些小的疏忽而使程序意外崩潰了;

只有在有些異常無法預知的情況下,才應該加上try...except,其他的邏輯錯誤應該盡量修正,盡量避免使用異常處理

套接字基礎

C/S架構

即客戶端/服務端架構,B/S架構(瀏覽器/服務器)也屬於C/S架構。

socket套接字就是為了完成C/S架構軟件的開發。

socket基礎的基礎

socket依賴於網絡,所以騷年,網絡基礎不能忘了

socket介紹

在python裏,socket子層位於TCP/IP協議棧的傳輸層和應用層的中間層,是一個提供向上向下接口的軟件抽象層。

socket封裝了tcp和udp協議,所以遵循socket語法寫出的程序是遵循tcp和udp協議的。

註意:socket=ip+port,ip用來標識網絡中主機的位置,port用來標識主機的應用,所以ip+port能夠標識互聯網中的唯一一個應用,所以說socket其實就是ip和端口的組合

socket分類

網絡編程只需要關註AF_INET,這種是應用最廣泛的,如果是用於ipv6平臺需要用AF_INET6。

其他:AF_UNIX,用於UNIX文件系統間通信、還有很多其他的平臺使用的,不多說

socket通信原理

技術分享

服務器端先初始化Socket,然後與端口綁定(bind),對端口進行監聽(listen)並調用accept阻塞,等待客戶端連接。

客戶端初始化一個Socket,然後連接服務器(connect),如果正常訪問到了服務器端,服務器端阻塞結束,連接成功,這時客戶端與服務器端的連接就建立了。

客戶端發送數據請求,服務器端接收請求並處理請求,然後服務器把回應數據發送給客戶端,客戶端讀取數據,循環。

最後客戶端或者服務器端關閉連接,一次交互結束。

socket模塊

一次性套接字通信(基於本地回環地址),以打電話的過程解釋

服務端:

技術分享
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #買手機
s.bind((‘127.0.0.1‘,9000)) #手機插卡,如果元組為(‘‘,9000)表示本機所有的網卡,相當於0.0.0.0
s.listen(5)     #手機待機,括號中的值是用於TCP連接的優化
conn,addr=s.accept()            #手機接電話
print(‘接到來自%s的電話‘ %addr[0])
msg=conn.recv(1024)             #聽消息,聽話
print(msg,type(msg))
conn.send(msg.upper())          #發消息,說話
conn.close()                    #掛電話
s.close()                       #手機關機
技術分享

客戶端:

技術分享
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)    #買手機
s.connect_ex((‘127.0.0.1‘,9000))           #撥電話
s.send(‘nb‘.encode(‘utf-8‘))         #發消息,說話(只能發送字節類型)
feedback=s.recv(1024)               #收消息,聽話
print(feedback.decode(‘utf-8‘))
s.close()                                       #掛電話
技術分享

執行先執行服務端,然後執行客戶端。

相關值說明:

1 socket.socket(socket_family,socket_type,protocal=0)
2 socket_family可以是 AF_UNIX 或 AF_INET
3 socket_type 可以是 SOCK_STREAM(面向連接的可靠數據傳輸,即TCP協議)或 SOCK_DGRAM(面向無連接的不可靠數據傳輸,即UDP)
4 protocol 一般不填,默認值為 0

相關方法說明:

技術分享
 1 服務端套接字函數
 2 s.bind()    綁定(主機,端口號)到套接字
 3 s.listen()  開始TCP監聽
 4 s.accept()  被動接受TCP客戶的連接,(阻塞式)等待連接的到來
 5 
 6 客戶端套接字函數
 7 s.connect()     主動初始化TCP服務器連接
 8 s.connect_ex()  connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常
 9 
10 公共用途的套接字函數
11 s.recv()            接收TCP數據
12 s.send()            發送TCP數據(send在待發送數據量大於己端緩存區剩余空間時,數據丟失,不會發完)
13 s.sendall()         發送完整的TCP數據(本質就是循環調用send,sendall在待發送數據量大於己端緩存區剩余空間時,數據不丟失,循環調用send直到發完)
14 s.recvfrom()        接收UDP數據
15 s.sendto()          發送UDP數據
16 s.getpeername()     連接到當前套接字的遠端的地址
17 s.getsockname()     當前套接字的地址
18 s.getsockopt()      返回指定套接字的參數
19 s.setsockopt()      設置指定套接字的參數
20 s.close()           關閉套接字
21 
22 面向鎖的套接字方法
23 s.setblocking()     設置套接字的阻塞與非阻塞模式
24 s.settimeout()      設置阻塞套接字操作的超時時間
25 s.gettimeout()      得到阻塞套接字操作的超時時間
26 
27 面向文件的套接字的函數
28 s.fileno()          套接字的文件描述符
29 s.makefile()        創建一個與該套接字相關的文件
技術分享

socket循環通信,即一個連接來了可以不斷的循環交互,有多個連接請求連接的時候如果第一個連接不中斷,則無法連接,當第一個連接中斷,第二個連接連上來,依次

服務器端:

技術分享
 1 import socket
 2 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #買手機
 3 s.bind((‘127.0.0.1‘,9000)) #手機插卡
 4 s.listen(5)     #手機待機,括號中的值是用於TCP連接的優化
 5 while True: #可以不停的接電話,即不停地接受連接
 6     conn,addr=s.accept()            #手機接電話
 7     print(‘接到來自%s的電話‘ %addr[0])
 8     while True:  #循環的收發消息
 9         msg=conn.recv(1024)             #聽消息,聽話
10         print(msg,type(msg))
11         conn.send(msg.upper())          #發消息,說話
12     conn.close()                    #掛電話
13 s.close()                       #手機關機
技術分享

客戶端:

技術分享
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #買手機
s.connect((‘127.0.0.1‘,9000)) #撥號
while True: #通訊循環
    msg=input(‘>>: ‘).strip()
    if not msg:continue
    s.send(msg.encode(‘utf-8‘))
    server_res=s.recv(1024)
    print(‘server_res: ‘,server_res.decode(‘utf-8‘))
phone_client.close()
技術分享

錯誤處理:

技術分享

由於服務端仍然存在四次揮手的time_wait狀態在占用地址(如果不懂,請深入研究1.tcp三次握手,四次揮手 2.syn洪水攻擊 3.服務器高並發情況下會有大量的time_wait狀態的優化方法)

解決

技術分享 windows 技術分享 linux

簡單SSH示例

服務端

技術分享
 1 import socket
 2 import subprocess
 3 ssh_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)   #生成socket實例對象
 4 ssh_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #重用地址,防止占用
 5 ssh_server.bind((‘127.0.0.1‘,8080))
 6 ssh_server.listen(5)
 7 print(‘server run...‘)
 8 while True:
 9     conn,client_addr=ssh_server.accept()  #循環等待連接
10     print(‘客戶端: ‘,client_addr)
11     while True: #通訊循環
12         try:
13             cmd=conn.recv(1024) #收消息
14             res=subprocess.Popen(cmd.decode(‘utf-8‘),       #執行命令
15                              shell=True,
16                              stdout=subprocess.PIPE,
17                              stderr=subprocess.PIPE)
18             stdout=res.stdout.read()    #標準輸出
19             stderr=res.stderr.read()    #標準輸入
20             std=stdout+stderr
21             conn.sendall(std)
22 
23         except Exception:
24             break
25     conn.close()    #斷連接,進入下一次連接等待
26 ssh_server.close() #關閉程序
技術分享

客戶端:

技術分享
 1 import socket
 2 ssh_client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 3 ssh_client.connect((‘127.0.0.1‘,8080))
 4 while True: #通訊循環
 5     cmd=input(‘>>: ‘).strip()
 6     if not cmd:continue
 7     ssh_client.send(cmd.encode(‘utf-8‘))
 8     cmd_res = ssh_client.recv(1024)
 9     print(cmd_res.decode(‘gbk‘)) #windows
10     # print(cmd_res.decode(‘utf-8‘)) #linux
11 ssh_client.close()
技術分享

Python開發基礎----異常處理、socket套接字基礎1