一、異常處理
1)異常處理的使用意義
1 什么是異常處理 異常是程序發生錯誤的信號,即程序一旦出錯就會立刻產生一個異常,如果該異常沒有被處理 那么異常就拋出來,程序的運行也隨之終止 異常分為三部分: 異常的類型 異常的內容、提示信息 異常的追蹤/定位信息信息 捕捉/檢測異常,一旦發生異常就立刻執行相應的處理邏輯,而不是任由異常拋出來終止程序 2 為何要進行異常處理 增強程序的健壯性 3 如何進行異常處理 try...except...
2)邏輯錯誤導致的異常

# int('xxxxxxx') #ValueError # age #NameError # for i in 10: #TypeError: # pass # l=[] # l[1111111] #IndexError # d={'x':1} # d['y'] #KeyError # 1 / 0 #ZeroDivisionError
3)異常處理的單分支結構

try: l=[1,2,3] l[100] print('====>') except IndexError: print('=====>NameError') print('其他代碼')
4)異常的多分支結構

try: age l=[1,2,3] # l[100] d={'x':1} # d['y'] print('====>') except NameError as e: print('NameError: %s' %e) except IndexError as e: print('IndexError: %s' %e) except KeyError as e: print('KeyError: %s' %e) print('其他代碼')
5)萬能異常:Exception,可以匹配所有種類的異常,最好不要直接萬能匹配異常

try: # age l=[1,2,3] # l[100] d={'x':1} d['y'] print('====>') except Exception as e: print(e) print('其他代碼')
6)多分支+Exception,注意Exception一定要放到except 其他異常的的后面

try: d={'x':1} d['y'] print('====>') except IndexError as e: print('IndexError: %s' %e) except KeyError as e: print('KeyError:%s' %e) except Exception as e: print(e) print('其他代碼')
7)try...else,else會在被檢測的代碼塊沒有異常發生的情況下執行, else一定要與except連用,並且一定要放到多個except后面

try: l=[1,2,3] print('====>') except IndexError as e: print('IndexError: %s' %e) except KeyError as e: print('KeyError:%s' %e) except Exception as e: print(e) else: print('else的代碼只有在被檢測的代碼塊沒有異常發生的情況下才會執行')
8)try...finally,finnaly的代碼會什么時候運行? finally應放到最后面,常應用於回收資源使用

try: f=open('a.txt','w') d={'x':1} print(d['y']) except KeyError as e: print('KeyError:%s' %e) except Exception as e: print(e) else: print('else的代碼只有在被檢測的代碼塊沒有異常發生的情況下才會執行') finally: print('finally的代碼,無論被檢測的代碼有無異常,都會執行,通常在finally內做一些回收資源的事情') f.close() print('其他代碼')
9)主動觸發異常raise 異常類型(’異常的內容‘)

print('===>1') raise TypeError('類型錯誤') print('===>2') # 應用於程序中自定義某種法則,一旦不遵循則會像拋出語法異常一樣,終止程序的運行
10)斷言,和代替raise觸發的異常

info=[1,2,3,4,5,6] # if len(info) != 7: # raise ValueError('值的個數 < 7') assert len(info) == 7 # 我斷定len(info) == 7,如果我斷言失敗,程序則拋出異常 print('階段2--->1')
11)自定義異常

class MyError(BaseException): def __init__(self,msg): super().__init__() self.msg=msg def __str__(self): return '<%s>' %self.msg raise MyError('我自己定義的異常')
二、socker套接字網絡編程,tcp連接方式
1)套接字工作流程
先從服務器端說起。服務器端先初始化Socket,然后與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端連接。在這時如果有個客戶端初始化一個Socket,然后連接服務器(connect),如果連接成功,這時客戶端與服務器端的連接就建立了。客戶端發送數據請求,服務器端接收請求並處理請求,然后把回應數據發送給客戶端,客戶端讀取數據,最后關閉連接,一次交互結束
2)實例化出簡單的服務端和客戶端程序

import socket #1、買手機 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式協議指的就是tcp協議 # print(phone) #2、插手機卡 phone.bind(('127.0.0.1',8080)) #端口范圍0-65535 #3、開機 phone.listen(5) #限制的是請求數,而非鏈接數 #4、等待電話連接 print('服務的啟動......') conn,client_addr=phone.accept() #(tcp的連接對象,客戶端的ip和端口) print(conn) print(client_addr) #5、收消息 data=conn.recv(1024) #最大接收1024bytes print('客戶端數據:%s' %data) #6、發消息 conn.send(data.upper()) #7、掛電話 conn.close() #9、關機 phone.close()

import socket #1、買手機 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式協議指的就是tcp協議 #2、打電話,建電話連接 phone.connect(('127.0.0.1',8080)) #ip和端口都是服務端的 #3、發消息 phone.send('hello world'.encode('utf-8')) #4、收消息 data=phone.recv(1024) print(data) #5、掛電話 phone.close()
3)加上通信循環

import socket #1、買手機 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式協議指的就是tcp協議 # print(phone) #2、插手機卡 phone.bind(('127.0.0.1',8080)) #端口范圍0-65535 #3、開機 phone.listen(5) #限制的是請求數,而非鏈接數 #4、等待電話連接 print('服務的啟動......') conn,client_addr=phone.accept() #(tcp的連接對象,客戶端的ip和端口) print(conn) print(client_addr) while True: # 通信循環 try: #針對的是windows系統 #5、收消息 data=conn.recv(1024) #最大接收1024bytes if not data:break #針對的linux系統 print('客戶端數據:%s' %data) #6、發消息 conn.send(data.upper()) except ConnectionResetError: break #7、掛電話 conn.close() #9、關機 phone.close()

import socket #1、買手機 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式協議指的就是tcp協議 #2、打電話,建電話連接 phone.connect(('127.0.0.1',8080)) #ip和端口都是服務端的 while True: msg=input('>>>: ').strip() #3、發消息 phone.send(msg.encode('utf-8')) #4、收消息 data=phone.recv(1024) print(data.decode('utf-8')) #5、掛電話 phone.close()
4)加上連接循環,可等待多個連接進來

import socket #1、買手機 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式協議指的就是tcp協議 # print(phone) # phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加 #2、插手機卡 phone.bind(('127.0.0.1',8081)) #端口范圍0-65535 #3、開機 phone.listen(5) #限制的是請求數,而非鏈接數 #4、等待電話連接 print('服務的啟動......') while True: # 連接循環 conn,client_addr=phone.accept() #(tcp的連接對象,客戶端的ip和端口) # print(conn) print(client_addr) # 通信循環 while True: try: #針對的是windows系統 #5、收消息 data=conn.recv(1024) #最大接收1024bytes if not data:break #針對的linux系統 print('客戶端數據:%s' %data) #6、發消息 conn.send(data.upper()) except ConnectionResetError: break #7、掛電話 conn.close() #9、關機 phone.close()

import socket #1、買手機 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式協議指的就是tcp協議 #2、打電話,建電話連接 phone.connect(('127.0.0.1',8081)) #ip和端口都是服務端的 while True: msg=input('>>>: ').strip() #msg='' if not msg:continue #3、發消息 phone.send(msg.encode('utf-8')) print('has send====>') #4、收消息 data=phone.recv(1024) print('has recv====>') print(data.decode('utf-8')) #5、掛電話 phone.close()
5)模擬ssh遠程執行命令

from socket import * import subprocess phone=socket(AF_INET,SOCK_STREAM) phone.bind(('127.0.0.1',8081)) phone.listen(5) print('服務的啟動......') # 連接循環 while True: conn,client_addr=phone.accept() print(client_addr) # 通信循環 while True: try: cmd=conn.recv(1024) if not cmd:break obj=subprocess.Popen(cmd.decode('utf-8'),shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdout=obj.stdout.read() stderr=obj.stderr.read() # conn.send(stdout+stderr) print(len(stdout)+len(stderr)) conn.send(stdout) conn.send(stderr) except ConnectionResetError: break conn.close() phone.close()

from socket import * phone=socket(AF_INET,SOCK_STREAM) phone.connect(('127.0.0.1',8081)) while True: cmd=input('>>>: ').strip() if not cmd:continue phone.send(cmd.encode('utf-8')) res=phone.recv(1024) #1024 * 8 print(res.decode('gbk')) phone.close()
發現了粘包問題
6)解決粘包問題

from socket import * import subprocess import struct phone=socket(AF_INET,SOCK_STREAM) phone.bind(('127.0.0.1',8081)) phone.listen(5) print('服務的啟動......') # 連接循環 while True: conn,client_addr=phone.accept() print(client_addr) # 通信循環 while True: try: cmd=conn.recv(1024) if not cmd:break obj=subprocess.Popen(cmd.decode('utf-8'),shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdout=obj.stdout.read() stderr=obj.stderr.read() # 1、先發送固定長度的報頭 #目前報頭里只包含數據的大小 total_size=len(stdout) + len(stderr) conn.send(struct.pack('i',total_size)) # 2、發送真實的數據 conn.send(stdout) conn.send(stderr) except ConnectionResetError: break conn.close() phone.close()

from socket import * import struct phone=socket(AF_INET,SOCK_STREAM) phone.connect(('127.0.0.1',8081)) while True: cmd=input('>>>: ').strip() if not cmd:continue phone.send(cmd.encode('utf-8')) #1、先收報頭,從報頭里取出對真實數據的描述信息 header=phone.recv(4) total_size=struct.unpack('i',header)[0] #2、循環接收真實的數據,直到收干凈為止 recv_size=0 res=b'' while recv_size < total_size: recv_data=phone.recv(1024) res+=recv_data recv_size+=len(recv_data) print(res.decode('gbk')) phone.close()
7)解決粘包報頭數據過大問題,先轉json,再轉報頭

from socket import * import subprocess import struct import json phone=socket(AF_INET,SOCK_STREAM) phone.bind(('127.0.0.1',8081)) phone.listen(5) print('服務的啟動......') # 連接循環 while True: conn,client_addr=phone.accept() print(client_addr) # 通信循環 while True: try: cmd=conn.recv(1024) if not cmd:break obj=subprocess.Popen(cmd.decode('utf-8'),shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdout=obj.stdout.read() stderr=obj.stderr.read() #制作報頭 header_dic={ 'filename':'a.txt', 'total_size':len(stdout) + len(stderr), 'md5':'xxxxxsadfasdf123234e123' } header_json = json.dumps(header_dic) header_bytes=header_json.encode('utf-8') #1、先發送報頭的長度 conn.send(struct.pack('i',len(header_bytes))) #2、再發送報頭 conn.send(header_bytes) #3、最后發送真實的數據 conn.send(stdout) conn.send(stderr) except ConnectionResetError: break conn.close() phone.close()

from socket import * import struct import json phone=socket(AF_INET,SOCK_STREAM) phone.connect(('127.0.0.1',8081)) while True: cmd=input('>>>: ').strip() if not cmd:continue phone.send(cmd.encode('utf-8')) #1、先收報頭的長度 obj=phone.recv(4) header_size=struct.unpack('i',obj)[0] #2、再接收報頭 header_bytes=phone.recv(header_size) header_json=header_bytes.decode('utf-8') header_dic=json.loads(header_json) print(header_dic) total_size=header_dic['total_size'] #3、循環接收真實的數據,直到收干凈為止 recv_size=0 res=b'' while recv_size < total_size: recv_data=phone.recv(1024) res+=recv_data recv_size+=len(recv_data) print(res.decode('gbk')) phone.close()
8) socketserver模塊實現並發的套接字通信
基於tcp的並發線程通信

import socketserver # 通信循環 class MyTCPHandler(socketserver.BaseRequestHandler): def handle(self): while True: try: data=self.request.recv(1024) if not data:break self.request.send(data.upper()) except ConnectionResetError: break self.request.close() if __name__ == '__main__': # 連接循環 server=socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyTCPHandler) server.serve_forever()

import socket client=socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) #ip和端口都是服務端的 while True: msg=input('>>>: ').strip() client.send(msg.encode('utf-8')) data=client.recv(1024) print(data.decode('utf-8')) client.close()
基於udp的並發線程通信

import socketserver # 通信循環 class MyUDPHandler(socketserver.BaseRequestHandler): def handle(self): # print(self.request) res=self.request[0] print('客戶端發來的數據:',res) self.request[1].sendto(res.upper(),self.client_address) if __name__ == '__main__': #連接循環 server=socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyUDPHandler) server.serve_forever()

import socket import os client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) while True: msg='%s hello' %os.getpid() client.sendto(msg.encode('utf-8'),('127.0.0.1',8080)) res,server_addr=client.recvfrom(1024) print(res)
三、socket套接字,基於UDP的連接方式
1)udp的工作模式

from socket import * import time server=socket(AF_INET,SOCK_DGRAM) # 數據報協議UDP #1、基於udp協議每發送的一條數據都自帶邊界,即udp協議沒有粘包問題 #2、基於udp協議的通信,一定是一發對應一收 server.bind(('127.0.0.1',8080)) while True: msg,client_addr=server.recvfrom(1024) # 接收客戶端的信息 print(msg ,client_addr) time.sleep(3) server.sendto(msg.upper(),client_addr) # 給客戶端回消息

from socket import * client=socket(AF_INET,SOCK_DGRAM) while True: # msg=input('>>: ').strip() client.sendto('egon'.encode('utf-8'),('127.0.0.1',8080)) # 給服務端發送消息 res,server_addr=client.recvfrom(1024) print(res)
2) udp的連接特點
1、一發對應一收 2、沒有粘包問題 3、只能接收數據量比較小的內容,如果接收的byte數量小於了發送的數量,會丟數據

from socket import * server=socket(AF_INET,SOCK_DGRAM) # 數據報協議UDP #1、基於udp協議每發送的一條數據都自帶邊界,即udp協議沒有粘包問題 #2、基於udp協議的通信,一定是一發對應一收 server.bind(('127.0.0.1',8080)) msg1,client_addr=server.recvfrom(1) print(msg1) msg2,client_addr=server.recvfrom(1) print(msg2) msg3,client_addr=server.recvfrom(1) print(msg3)

from socket import * client=socket(AF_INET,SOCK_DGRAM) client.sendto('hello'.encode('utf-8'),('127.0.0.1',8080)) client.sendto('world'.encode('utf-8'),('127.0.0.1',8080)) client.sendto('egon'.encode('utf-8'),('127.0.0.1',8080))
原文鏈接:http://www.cnblogs.com/linhaifeng/articles/6129246.html