#使用面向?qū)ο蠼鉀Qdatetime.tody()無法序列化的問題
import json
from datetime import datetime,date
# print(date.today()) #年月日 2020-12-08
# print(datetime.today()) #年月日時分秒 2020-12-08 16:07:34.919540
class Myjson (json.JSONEncoder):
def default(self, o):
if isinstance(o,datetime):
return o.strftime('%Y-%m-%d %X')
elif isinstance(o,date):
return o.strftime('%Y-%m-%d')
else:
return super().default(self,o)
res = {'c1':datetime.today(),'c2':date.today()}
print(json.dumps(res,cls=Myjson))
網(wǎng)絡編程之 TCP
#學習網(wǎng)絡編程可以開發(fā)一個cs架構(gòu)的軟件
#學習并發(fā)、數(shù)據(jù)庫、前端、django可以開發(fā)bs架構(gòu)的軟件
#軟件開發(fā)架構(gòu)
C/S架構(gòu)(client/server)
C:客戶端,APP
S:服務端,架構(gòu)
B/S架構(gòu)(browser/server)
B:瀏覽器,taobao.com/jd.com
S:服務端
bs架構(gòu)實際上也是cs架構(gòu)
統(tǒng)一接口:比如微信、支付寶
#服務端
24小時不間斷提供服務
#客戶端
什么時候想體驗服務,什么時候去找心儀的服務端尋求服務
#網(wǎng)絡編程發(fā)展史
任何先進的技術(shù)基本上都是來源于軍事
#回到過去
1.早期的電話電話線
2.大屁股電腦網(wǎng)線
3.筆記本電腦,無線電話 網(wǎng)卡
#要想實現(xiàn)遠程通信,第一個需要具備的條件是:物理連接介質(zhì)
人想要實現(xiàn)交流必須統(tǒng)一語言 >>> 英文
計算機想要與計算機遠程通信,除了有物理連接介質(zhì)之外,還需要有一套公共的標準和協(xié)議
#OSI協(xié)議
OSI七層協(xié)議
應用層
HTTP協(xié)議:超文本傳輸協(xié)議
HTTPS協(xié)議
FTP協(xié)議
表示層
會話層
傳輸層
TCP協(xié)議/UDP協(xié)議,都是基于端口工作的協(xié)議
TCP:流式協(xié)議、可靠協(xié)議(反饋機制),慢,打電話
基于TCP協(xié)議通信,必須先建立雙向通道:TCP協(xié)議的三次握手、四次揮手
三次握手:
洪水攻擊,一臺服務器在短時間內(nèi)接收到了大量的請求
四次揮手:
time_wait
UDP:數(shù)據(jù)報協(xié)議,不可靠的協(xié)議,快,發(fā)短信,QQ
無序建立雙向通道,數(shù)據(jù)的傳輸不安全
端口:用來唯一標識計算機上的某個應用程序(0~65535),統(tǒng)常0~1024這些都是操作系統(tǒng)默認使用的端口號,建議手動指定8000以后的端口號(訪問端口,輸出端口)
mysql3306
redis6379
djando8000
flask5000
tomcat8080
IP 端口:唯一標識接入互聯(lián)網(wǎng)的一臺計算機上的某個應用程序
域名解析:URL DNS
網(wǎng)絡層
IP協(xié)議,規(guī)定了只要是接入互聯(lián)網(wǎng)的計算機都必須有一個IP地址(公網(wǎng)、私網(wǎng))
IP地址的特點:點分十進制(0.0.0.0 255.255.255.255)
IP地址目前有兩個版本:IPV4、IPV6
路由器:實現(xiàn)局域網(wǎng)與局域網(wǎng)之間的互連
交換機:功能強大的路由器,讓連接了交換機的計算機,實現(xiàn)彼此之間的互連
局域網(wǎng):是構(gòu)成互聯(lián)網(wǎng)的基本單位
數(shù)據(jù)鏈路層
1.規(guī)定電信號的分組方式
2.規(guī)定了任何一臺接入互聯(lián)網(wǎng)的計算機,都必須有一塊網(wǎng)卡,該網(wǎng)卡上有世界上獨一無二的編號(mac地址),該編號由12位16進制數(shù)組成(前六位是廠商編號,后六位是流水線編號)
#1、2統(tǒng)稱為以太網(wǎng)協(xié)議(通信基本靠吼)(局域網(wǎng)內(nèi)使用)
1.廣播風暴(廣播、單播)
#ARP協(xié)議:根據(jù)ip地址,獲取Mac地址,本地緩存
物理連接層
基于電信號,傳輸0100010001這樣的二進制數(shù)據(jù)
OSI五層協(xié)議
應用層
傳輸層
網(wǎng)絡層
數(shù)據(jù)鏈路層
物理連接層
#應用程序所需要的的數(shù)據(jù),都是跟程序所在的那臺計算機的內(nèi)存去要
#TCP協(xié)議之所以可靠的原因在于反饋機制
反饋機制:計算機每次發(fā)數(shù)據(jù)的時候,必須等到對方的才會將內(nèi)存中的數(shù)據(jù)清除,否則會在一定的時間內(nèi),每隔一段時間發(fā)送一次
socket(套接字)
Ji
#server
import socket
server = socket.socket() #不傳參數(shù),默認使用的就是TCP協(xié)議,買手機
server.bind(('127.0.0.1',8080)) #bind內(nèi)為元組,127.0.0.1,為本地回環(huán)地址,插電話卡
server.listen(5) #半連接池,開機
conn,addr = server.accept() #接聽電話,一直等待(阻塞)
data = conn.recv(1024) #聽別人說話,接收1024個字節(jié),阻塞
print(data)
conn.send(b'hello baby') #給別人回話
conn.close() #掛電話
server.close() #關(guān)機
#client
import socket
client = socket.socket() #拿電話
client.connect(('127.0.0.1',8080)) #撥號,寫對方的ip和端口
client.send(b'hello world') #對別人說話
data = client.recv(1024) #聽別人說話,阻塞
print(data)
client.close() #掛電話
#send()與recv()不要出現(xiàn)兩邊相同的情況
#recv()是跟內(nèi)存要數(shù)據(jù),至于數(shù)據(jù)的來源,recv不管
循環(huán)通信
#server
import socket
server = socket.socket() #生成一個對象
server.bind(('127.0.0.1',8080)) #綁定ip和端口
server.listen(5) #半連接池
conn,addr = server.accept() #阻塞
while True:
data = conn.recv(1024) #聽別人說話,接收1024個字節(jié)
print(data)
conn.send(data.upper()) #給別人回話
# conn.close() #掛電話
# server.close() #關(guān)機
#client
import socket
client = socket.socket() #生成一個對象
client.connect(('127.0.0.1',8080))
while True:
msg = input('請輸入要發(fā)送的內(nèi)容>>>: ').encode('utf-8')
client.send(msg) #對別人說話
data = client.recv(1024) #聽別人說話
print(data)
# client.close()
socket通信的一些問題
#server
import socket
server = socket.socket() #生成一個對象
server.bind(('127.0.0.1',8080)) #綁定ip和端口
server.listen(5) #半連接池
conn,addr = server.accept() #阻塞,addr就是客戶端的地址
while True:
try:
data = conn.recv(1024) #conn()類似于雙向通道
print(data) #Mac和linux客戶端異常退出之后,服務端不會報錯,會一致接收b''
if len(data) == 0:break
conn.send(data.upper()) #給別人回話
except ConnectionResetError as e:
print(e)
break
conn.close() #掛電話
server.close() #關(guān)機
#client
import socket
client = socket.socket() #生成一個對象
client.connect(('127.0.0.1',8080))
while True:
msg = input('請輸入要發(fā)送的內(nèi)容>>>: ').encode('utf-8')
if len(msg) == 0:continue #解決客戶端輸入空,resc()同時出現(xiàn)的情況
client.send(msg) #對別人說話
data = client.recv(1024) #聽別人說話
print(data)
# client.close()
連接循環(huán)
#服務端
固定的ip和端口
24小時不間斷提供服務
#server
import socket
server = socket.socket() #生成一個對象
server.bind(('127.0.0.1',8080)) #綁定ip和端口
server.listen(5) #半連接池,允許最大的等待數(shù)(連接數(shù)為6)
while True:
conn,addr = server.accept() #阻塞,addr就是客戶端的地址
while True:
try:
data = conn.recv(1024) #conn()類似于雙向通道
print(data) #Mac和linux客戶端異常退出之后,服務端不會報錯,會一致接收b''
if len(data) == 0:break
conn.send(data.upper()) #給別人回話
except ConnectionResetError as e:
print(e)
break
conn.close() #掛電話
# server.close() #關(guān)機
#client
import socket
client = socket.socket() #生成一個對象
client.connect(('127.0.0.1',8080))
while True:
msg = input('請輸入要發(fā)送的內(nèi)容>>>: ').encode('utf-8')
if len(msg) == 0:continue #解決客戶端輸入空,resc()同時出現(xiàn)的情況
client.send(msg) #對別人說話
data = client.recv(1024) #聽別人說話
print(data)
# client.close()
模擬終端
#subprocess模塊
import subprocess
while True:
cmd = input('請輸入您的命令>>>: ')
obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
print(obj.stdout.read().decode('gbk')) #正確命令返回結(jié)果,windows默認使用gbk編碼
print(obj.stderr.read().decode('gbk')) #錯誤命令返回結(jié)果
TCP協(xié)議的粘包問題
#TCP協(xié)議的特點
會將數(shù)據(jù)量比較小的,并且時間間隔比較短的數(shù)據(jù)一次性打包發(fā)給對方
#server
import socket
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
conn,addr = server.accept()
data = conn.recv(5)
print(data)
data = conn.recv(5)
print(data)
data = conn.recv(4)
print(data)
conn.send(b'hello baby')
conn.close()
server.close()
#client
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
client.send(b'hello')
client.send(b'world')
client.send(b'baby')
data = client.recv(8)
print(data)
client.close()
#少的數(shù)據(jù)量將會一次打包發(fā)送給服務端,節(jié)省資源
#如果知道數(shù)據(jù)的發(fā)送方發(fā)送的字節(jié)數(shù),那么雙方的信息就可以不用在擔心'字節(jié)長度問題'
struct模塊
#struct模塊
可以將任意字符串打包成字節(jié)長度為4的包,解包后仍可以得到原來字符串的長度
當原始數(shù)據(jù)特別大的時候,i模式裝不下了,這個時候就需要更換模式
import struct
str = 'evfreatteg.t.g..t;hyh;y;5;yjjjjjn'
print('原始的: ',len(str))
str1 = struct.pack('i',len(str)) #將數(shù)據(jù)打包
print(len(str1)) #包長度固定位4
str2 = struct.unpack('i',str1)[0] #將數(shù)據(jù)解包
print('解包后的: ',str2)
原始的: 33
4
解包后的: 33
使用struct模塊解決粘包問題
#解決粘包問題
服務端:
1.先制作一個要發(fā)送給客戶端的字典
2.制作字典的報頭
3.發(fā)送字典的報頭
4.發(fā)送字典
5.再發(fā)送真實數(shù)據(jù)長度
客戶端:
1.先接受字典的報頭
2.解析拿到字典的數(shù)據(jù)長度
3.接收字典
4.從字典中獲取真實數(shù)據(jù)長度
5.接收真實數(shù)據(jù)
#server
import socket
import subprocess
import struct
import json
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn,addr = server.accept()
while True:
try:
cmd = conn.recv(1024)
if len(cmd) == 0:break
cmd = cmd.decode('utf-8')
obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
res = obj.stdout.read() obj.stderr.read()
d = {'name':'syy','file_size':len(res),'info':'大家為我驕傲'}
json_d = json.dumps(d)
#1.先制作一個字典的報頭
header = struct.pack('i',len(json_d))
#2.發(fā)送字典報頭
conn.send(header)
#3.發(fā)送字典
conn.send(json_d.encode('utf-8'))
#4.再發(fā)送真實數(shù)據(jù)
conn.send(res)
# conn.send(obj.stdout.read()) #只能read()一次
# conn.send(obj.stderr.read())
except ConnectionResetError as e:
print(e)
break
conn.close()
# server.close() #關(guān)機
#client
import socket
import struct
import json
client = socket.socket() #生成一個對象
client.connect(('127.0.0.1',8080))
while True:
msg = input('請輸入要發(fā)送的內(nèi)容>>>: ').encode('utf-8')
if len(msg) == 0:continue #解決客戶端輸入空,resc()同時出現(xiàn)的情況
client.send(msg) #對別人說話
#1.先接收字典報頭
header_dict = client.recv(4)
#2.解析報頭,獲取字典長度
dict_size = struct.unpack('i',header_dict)[0]
#3.循環(huán)接收字典數(shù)據(jù)
dict_bytes = client.recv(dict_size)
dict_json = json.loads(dict_bytes.decode('utf-8'))
#4.從字典中獲取信息
print(dict_json)
recv_size = 0
real_data = b''
while recv_size < dict_json.get('file_size'):
data = client.recv(1024)
real_data = data
recv_size = len(data)
print(real_data.decode('gbk'))
# client.close()
練習
#習題
寫一個上傳電影的功能
1.循環(huán)打印某一個文件夾下面的所有的文件
2.用戶想要上傳的文件
3.將用戶選擇的文件上傳到服務器
4.服務端保存該文件
#server
import socket
import subprocess
import struct
import json
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn,addr = server.accept()
while True:
try:
header_len = conn.recv(4)
#解析字典報頭
header_len = struct.unpack('i',header_len)[0]
#在接收字典數(shù)據(jù)
header_dic = conn.recv(header_len)
real_dic = json.loads(header_dic.decode('utf-8'))
#獲取真實數(shù)據(jù)長度
total_size = real_dic.get('file_size')
#循環(huán)接收并寫入文件
recv_size = 0
with open(real_dic.get('file_name'),'wb') as f:
while recv_size < total_size:
data = conn.recv(1024)
f.write(data)
recv_size = len(data)
print('上傳成功')
except ConnectionResetError as e:
print(e)
break
conn.close()
# server.close() #關(guān)機
#client
import socket
import struct
import json
import os
client = socket.socket() #生成一個對象
client.connect(('127.0.0.1',8080))
while True:
#獲取電影列表,循環(huán)展示
MOVIE_DIR = r'D:\python視頻\day29\視頻'
movie_list = os.listdir(MOVIE_DIR)
for i,movie in enumerate(movie_list,1):
print(i,movie)
#用戶選擇
choise = input('請輸入電影序號>>>: ').strip()
#判斷是否是數(shù)字字符串
if choise.isdigit():
choise = int(choise)
#判斷用戶輸入的值的范圍是否有效
if choise in range(1,len(movie_list) 1):
#獲取到用戶想要上傳的文件名
path = movie_list[choise-1]
#拼接文件的絕對路徑
file_path = os.path.join(MOVIE_DIR,path)
#獲取文件大小
file_size = os.path.getsize(file_path)
#定義一個字典
res_d = {
'file_name':path,
'file_size':file_size,
'msg':'尼桑~'
}
#序列化字典
json_d = json.dumps(res_d)
json_bytes = json_d.encode('utf-8')
#1.制作字典格式報頭
header = struct.pack('i',len(json_bytes))
#2.發(fā)送字典報頭
client.send(header)
#3.再發(fā)字典
client.send(json_bytes)
#4.再發(fā)文件數(shù)據(jù),打開文件循環(huán)發(fā)送
with open(file_path,'rb') as f:
for line in f:
client.send(line)
else:
print('請輸入數(shù)字序號!')
異常處理
#什么是異常
程序在運行過程中,出現(xiàn)不可預知的錯誤
并且該錯誤沒有對應的處理機制,那么就會以異常的形式表現(xiàn)出來
造成的影響是整個程序無法正常運行
#異常的結(jié)構(gòu)
1.異常的類型NAMEERROP
2.異常的信息name 'hhhhhhh' is not defined
3.異常的位置File "E:/python_test/a.py", line 6, in <module>
#異常的種類
1.語法錯誤
是程序員可以立刻解決的,這種錯誤是不能容忍的
2.邏輯錯誤
這種錯誤是可以被容忍的,因為一眼看不出來
針對邏輯上的錯誤,可以采用異常處理機制進行捕獲
#常見的錯誤類型
1.名字錯誤NAMEERROP,變量名、函數(shù)名、類名不存在
2.語法錯誤SyntaxError,if/while
3.鍵不存在KeyError
d = {'name':'syy'}
print(d['password'])
4.值錯誤ValueError
int('ssss')
5.索引錯誤IndexError
l = [1,2,3]
print(l[111])
6.關(guān)鍵字assert斷言錯誤 AssertionError
#異常處理
在你認為可能會出現(xiàn)bug的代碼塊上方try一下(try代碼塊越少越好)
#異常處理的格式
try:
想要監(jiān)控的代碼塊
except 錯誤類型:
監(jiān)控到錯誤類型后自定義的反饋
try:
想要監(jiān)控的代碼塊
except 錯誤類型 as e:#e代表本來代碼的錯誤反饋
監(jiān)控到錯誤類型后自定義的反饋
try:
想要監(jiān)控的代碼塊
except 錯誤類型:
監(jiān)控到錯誤類型后自定義的反饋
else:
print('被檢測的代碼沒有任何異常發(fā)生,才會走else')
finally:
print('被檢測的代碼無論有沒有異常發(fā)生,都會走finally')
#例
try:
name
except NameError:
print('NameError已被我處理')
#except可以跟多個
try:
# name
# l = [1,2,3]
# l[100]
# d = {'name':'syy'}
# d['password']
# if#語法錯誤不能被監(jiān)控
int('www')
except NameError:
print('NameError已被我處理')
except IndexError:
print('IndexError已被我處理')
except KeyError:
print('KeyError已被我處理')
except SyntaxError:
print('SyntaxError已被我處理')
except ValueError:
print('ValueError已被我處理')
#萬能異常捕獲
try:
# name
# l = [1,2,3]
# l[100]
# d = {'name':'syy'}
# d['password']
# if
int('www')
except Exception:#萬能異常捕獲,繼承自BaseException
print('所有異常已被我處理')
#else語法
try:
# name
# l = [1,2,3]
# l[100]
# d = {'name':'syy'}
# d['password']
# if
int('1')
except Exception:
print('所有異常已被我處理')
else:
print('被檢測的代碼沒有任何異常發(fā)生,才會走else')
finally:
print('被檢測的代碼無論有沒有異常發(fā)生,都會走finally')
拋出異常
#關(guān)鍵字raise,就是主動拋出異常
if 'syy' == 'cool':
pass
else:
raise NameError('我覺得不對...')
斷言錯誤
#關(guān)鍵字assert
在關(guān)鍵字assert預言的位置,如果語言對了,代碼正常執(zhí)行,錯了的話,報AssertionError錯誤
l = [1,2,3]
assert len(l) > 0
print('斷言對了才會走這行代碼')
自定義異常
#主動拋出異常,其實就是將異常類的對象打印出來,會走__str__方法(對象的屬性被打印的時候觸發(fā))
class MyError(BaseException):
def __init__(self,msg):
super().__init__()
self.msg = msg
def __str__(self):
return '<%shhhhhh>' %self.msg
raise MyError('自定義異常')
網(wǎng)絡編程之 UDP
UDP通信的基本使用
#UDP通信
數(shù)據(jù)包協(xié)議自帶報頭
基于UDP協(xié)議的數(shù)據(jù)傳輸,數(shù)據(jù)是不安全的(客戶端只發(fā),無論服務端有沒有接收)
#server
import socket
server = socket.socket(type=socket.SOCK_DGRAM) #UDP協(xié)議
server.bind(('127.0.0.1',8080))
#UDP沒有半連接池的概念不需要設置半連接池
#因為沒有雙向通道,所以不需要accept,直接設置通信循環(huán)即可
while True:
data,addr = server.recvfrom(1024)
print('數(shù)據(jù)',data) #客戶端發(fā)來的消息
print('地址',addr) #客戶端地址
server.sendto(data.upper(),addr)
#client
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
#不需要建立連接,直接進入通訊循環(huán)
server_address = ('127.0.0.1',8080)
while True:
client.sendto(b'hellow',server_address)
data,addr = client.recvfrom(1024)
print('服務端發(fā)來的數(shù)據(jù)',data)
print('服務端的地址',addr)
#UDP類似于發(fā)短信,TCP類似于打電話
UDP協(xié)議與TCP協(xié)議的異同
#TCP協(xié)議
1.TCP協(xié)議客戶端允許為空
2.TCP協(xié)議存在粘包問題
3.udp協(xié)議服務端不存在的情況下,客戶端照樣會報錯
4.TCP協(xié)議不支持并發(fā),使用模塊可以做到并發(fā)
#UDP協(xié)議
1.udp協(xié)議客戶端允許為空?是的
2.udp協(xié)議不會粘包?會的
3.udp協(xié)議服務端不存在的情況下,客戶端照樣不會報錯?會報錯,client.recvfrom(1024)報錯
4.udp協(xié)議支持并發(fā)是的
#并發(fā):看起來像是同時運行
#并行:真正意義上的同時運行
基于UDP協(xié)議實現(xiàn)簡易版的QQ
#server
import socket
server = socket.socket(type=socket.SOCK_DGRAM) #UDP協(xié)議
server.bind(('127.0.0.1',8080))
while True:
data,addr = server.recvfrom(1024)
print(data.decode('utf-8')) #客戶端發(fā)來的消息
msg = input('請輸入你要發(fā)送的內(nèi)容>>>: ').strip()
server.sendto(msg.encode('utf-8'),addr)
#client
import socket
client = socket.socket(type=socket.SOCK_DGRAM)
server_address = ('127.0.0.1',8080)
while True:
msg = input('請輸入您要發(fā)送的內(nèi)容(客戶端1)>>>: ').strip()
client.sendto(msg.encode('utf-8'),server_address)
data,addr = client.recvfrom(1024)
print(data.decode('utf-8'))
socketserver模塊
模塊的簡單使用
#server
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
print('來了?老弟')
#創(chuàng)建一個基于TCP的對象
#只要有客戶端連接,會自動交給自定義類中的handler方法去處理
server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer)
#啟動該服務的對象
server.serve_forever()
#client
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
socketserver模塊使TCP協(xié)議支持并發(fā)
#server
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
# print('來了?老弟')
while True:
data = self.request.recv(1024)
print(self.client_address) #客戶端地址
print(data.decode('utf-8'))
self.request.send(data.upper())
#村趕緊啊一個基于TCP的對象
server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer)
#啟動該服務的對象
server.serve_forever()
#client
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
client.send(b'hello')
data = client.recv(1024)
print(data.decode('utf-8'))
socketserver模塊與UDP協(xié)議
#server
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
# print('來了?老弟')
while True:
data,sock = self.request
print(self.client_address) #客戶端地址
print(data.decode('utf-8'))
sock.sendto(data.upper(),self.client_address)
#村趕緊啊一個基于TCP的對象
server = socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyServer)
#啟動該服務的對象
server.serve_forever()
#client
import socket
import time
client = socket.socket(type=socket.SOCK_DGRAM)
server_address = ('127.0.0.1',8080)
while True:
client.sendto(b'hello',server_address)
data,addr = client.recvfrom(1024)
print(data.decode('utf-8'),addr)
time.sleep(1)
來源:https://www./content-1-782451.html
|