今日大綱:html
1.FTP上傳簡單示例(詳細代碼)python
2.socketserver簡單示例&源碼介紹算法
3.驗證合法性鏈接//[祕鑰加密(urandom,sendall)(注意:中文的!不能用)]json
內容回顧:windows
(1)TCP(流)兩種黏包現象
1.連續(兩次發送的時間間隔很短暫)發送(send)兩個小包,被優化算法nagle,
給合併到了一塊兒,形成了黏包
2.一次性接收的數據,並無將發送的數據徹底接受完,第二次接收數據的時候,
會把第一次剩餘的數據給接收過來
UDP不會發生黏包現象,
(2)解決方案:
思想:先接收長度,再接收數據(根據長度拿取數據)
兩種解決方案:
1.發送真實數據以前,先發送數據的長度,接收方接收到長度以後,先回復一個確認信息,
發送端再發送真實的數據,接收方按照先發送來的數據長度來接收後面的真實數據.
2.struct
A:struct.pack('i',數字)
B:struct.unpack('i',bytes) 元組類型,須要索引取數據
(3)緩衝區:解決代碼的耦合性(從內存中開闢出的一塊空間)
輸出緩衝區
輸入緩衝區
conn,addr=>長鏈接
(4)
subprocess模塊
注意命令:用gbk進行解碼處理,由於windows中文版,默認編碼是gbk
1.FTP上傳簡單示例(詳細代碼)dom
服務端:socket
#重點案例 import socket import json import struct server=socket.socket() server.bind(('127.0.0.1',8001)) server.listen() conn,addr=server.accept() #首先接收文件的描述信息的長度 struct_data_len=conn.recv(4) data_len=struct.unpack('i',struct_data_len)[0] #經過文件信息的長度將文件的描述信息所有接收 print('data_len>>>',data_len) file_info_bytes=conn.recv(data_len) #將字符串轉換成bytes類型 #將文件描述信息轉換爲字典類型,一遍操做 file_info_json=file_info_bytes.decode('utf-8') file_info_dict=json.loads(file_info_json)#{'file_name': 'aaa.mp4', 'file_size': 24409470} print(file_info_dict) #統計每次接收的累計長度 recv_sum=0 with open('F:\S18\gg\aaa.mp4','wb') as f: while 1: every_recv_data=conn.recv(1024) print() #問題:文件名稱不知道這樣寫不合適, #因此,文件須要先發送文件信息
客戶端:優化
#需求:客戶端給服務端上傳文件,一句給的文件信息保存文件 import os import json import struct import socket client=socket.socket() client.connect(('127.0.0.1',8001)) file_size=os.path.getsize(r'F:\Python_workspace_S18\week7\day29\02 ftp上傳簡單示例\aaa.mp4')#首先統計數據的長度 #傳文件的信息,大小,文件名 file_info={ 'file_name':'aaa.mp4', #文件的名稱 'file_size':file_size, #文件的大小 #路徑等等 #客戶端給服務端傳遞文件,客戶端須要循環接收數據大小, # 還有文件名,還有服務端的那個路徑下,這裏沒有設置服務端的路徑(參考網上設置) # 或者可能老師後期可能講解 } #這裏pickle用的少,因此用json比較多,咱們這裏用json #思考:字典發送給服務端,轉換成bytes類型的,這裏必須用json #因爲字典沒法直接轉換成bytes類型的數據,因此須要json來將字典轉換爲 file_info_json=json.dumps(file_info) #將字符串轉換成bytes類型的數據 file_info_byte=file_info_json.encode('utf-8') #爲了防止黏包現象,將文件描述信息的長度打包後和文件的描述信息的數據一塊兒發送過去 data_len=len(file_info_byte) data_len_struct=struct.pack('i',data_len) #發送文件描述信息 client.send(data_len_struct+file_info_byte) #定義一個變量,=0,做爲每次讀取文件的長度的累計值 sum=0 #打開的aaa.mp4文件,rb的形式, with open('aaa.mp4','rb') as f: #循環讀取文件內容 while sum<file_size: #等於的時候已經讀完了 ##每次讀取文件的內容,每次讀取1024b字節 every_read_data=f.read(1024) #每次讀1024個字節, #當最後一次的數據不夠1024的時候,接收不夠的也是不會報錯的 sum+=len(every_read_data) client.send(every_read_data)#每次發送1024個字節 #打開數據文件都是隻有一行 #read能夠控制讀取的數據的長度 #readline不能夠控制讀取的數據的長度 #思考:數據的長度問題? #死循環怎麼結束這個循環? #鍛鍊本身的邏輯能力 #數據讀完怎麼跳出來? #統計每次讀的數據的長度 #首先統計數據的長度os模塊
重點回顧&補充編碼
import os file_size=os.path.getsize(r'F:\Python_workspace_S18\week7\day29\02 ftp上傳簡單示例\aaa.mp4') print(file_size) #4966541 file_info = { 'file_name':'aaa.mp4', 'file_size':file_size, } by_dic1 = bytes(str(file_info)+'中國',encoding='gbk')#b"{'file_name': 'aaa.mp4', 'file_size': 4966541}" by_dic = bytes(str(file_info)+'中國',encoding='utf-8')#b"{'file_name': 'aaa.mp4', 'file_size': 4966541}" print(by_dic1) print(by_dic) k=os.urandom(4) print(k,type(k),len(k)) s=bytes('中國',encoding='utf-8') s=bytes([1,2,3,4]) print(s,type(s)) '''
結果:
4966541 b"{'file_name': 'aaa.mp4', 'file_size': 4966541}\xd6\xd0\xb9\xfa" b"{'file_name': 'aaa.mp4', 'file_size': 4966541}\xe4\xb8\xad\xe5\x9b\xbd" b'\xd7n+y' <class 'bytes'> 4 b'\x01\x02\x03\x04' <class 'bytes'> '''
2.socketserver簡單示例&源碼介紹加密
簡單示例
服務端:
#原理:就是一個簡單模塊的簡單使用,不要想的太難 #這個服務端啓用一個,能夠啓動多個客戶端進行同時交流 #注意:這個是先從客戶端向服務端發送消息,再從服務端回客戶端消息 import socketserver class Myserver(socketserver.BaseRequestHandler): #定義類 def handle(self): while 1: from_client_msg=self.request.recv(1024) #self.request=conn print(from_client_msg.decode('utf-8')) msg=input('服務端說:') self.request.send(msg.encode('utf-8')) if __name__=='__main__': ip_port=('127.0.0.1',8001) server=socketserver.ThreadingTCPServer(ip_port,Myserver) #調用模塊的方法(線程TCP服務) #參數:接口&自定義繼承類 #server至關於一個對象,也就是建立了這麼個對象 server.serve_forever() #而這裏server對象調用serve_forever方法,至關因而開啓永遠的服務 ''' #推薦思路:(源碼問題) socketserver源碼,要練習看一下. python怎麼看源碼(百度試着看看教程) '''
客戶端:
import socket client=socket.socket() client.connect(('127.0.0.1',8001)) while 1: msg=input('客戶端說>>>') client.send(msg.encode('utf-8')) from_server_msg=client.recv(1024) print(from_server_msg.decode('utf-8'))
源碼介紹:(這個地方就是提高本身的地方)
超哥blog:(主要是socketserver的源碼解讀)
https://www.cnblogs.com/clschao/articles/9593164.html
女神blog:
解讀python中socket的源碼(http://www.cnblogs.com/Eva-J/p/5081851.html)
3.驗證合法性鏈接//[祕鑰加密(urandom,sendall)(注意:中文的!不能用)]