py6.6
#文件的上傳和下載:
#自定義一個字典,讓用戶選擇功能(上傳/下載)。將要上傳的文件路徑傳入,找到文件名,打開文件,計算文件大小,
#將功能、文件名、文件大小定義成一個字典,通過stuct模塊和json模塊固定字典的長度為4并序列化,以便防止發送
#時與后面要發送的文件內容出現黏包現象。通過循環將文件按照固定的大小(1024)分次發送到服務端。服務端也根據收到
#的文件大小來分次接收。
#struct模塊
# import struct
# #
# r = struct.pack('i',10) #將10變成一個固定的長度4的字符串
# print(len(r))
# print(r)
# print(struct.unpack('i',r))#解開,得到的是一個元祖形式,原數值在元祖的第0個元素。# import json
# dic = {'a': '1'}
# r = json.dumps(dic)
# print(json.loads(r))
server:import socket
import struct
import jsonsk = socket.socket()sk.bind(('127.0.0.1',8080))sk.listen(5)conn , addr = sk.accept()r = conn.recv(4) #接收從客戶端處已經被struct模塊將原字典長度轉換成固定長度的bytes(長度為4)
len_dic = struct.unpack('i',r)[0]#將這個bytes解開,變成一個元祖,要的是第一個元素-->原字典的長度。
# print(len_dic)
str_dic = conn.recv(len_dic).decode('utf-8')#根據原字典的長度來接收被序列化了字典
# print(str_dic)
str_dic = json.loads(str_dic)#將字典反序列化if str_dic['opt'] == 'upload':name = 'new_' + str_dic['name']#防止重名,加一個前綴。with open(name,mode='wb') as f:#以bytes類型直接寫進文件。file_size = str_dic['file_size']#獲取傳入文件的大小。while file_size:content = conn.recv(1024)#分次接收。f.write(content) #接收一次寫入一次。file_size -= len(content)#剩余的大小。
conn.close()#TCP協議兩個套接字。
sk.close()client:import socket
import os
import json
import structsk = socket.socket()sk.connect(('127.0.0.1',8080))dic_c = {'1':'upload','2':'download'} #定義一個供用戶選擇的字典while 1:num = input('請輸入序號').strip()if num == '1':for k,v in dic_c.items():#將字典展示出來。print(k,':',v)path = input('請輸入一個文件路徑').strip()name = os.path.basename(path) #獲取文件名,傳入服務端,寫入文件用。file_size = os.path.getsize(path)#獲取文件大小,用來循環并分次傳輸。dic = {'opt': dic_c[num],'name':name,'file_size':file_size}#將功能、文件名、大小作為字典傳入服務端。str_dic = json.dumps(dic) #將字典序列化,變成字符串,才能傳輸。len_dic = len(str_dic) #計算序列化后的字典的長度。r = struct.pack('i',len_dic)#通過序列號后的字典的長度將其變成長度為固定4位的bytes.sk.send(r) #將固定后的bytes傳入服務端。sk.send(str_dic.encode('utf-8'))#另一端已經解出了序列化后字典的長度,發送即可。with open(name,mode='rb') as f:#以bytes類型讀取,就不用轉碼了。while file_size:content = f.read(1024)#分次讀取sk.send(content) #分次傳輸,直到傳到沒有為止。另一端也是與此同樣來分次接收file_size -= len(content)break
sk.close() 文件上傳
?
#執行系統命令:subprocess模塊 # import subprocess # # res = subprocess.Popen('dir',shell=True,#告訴系統把'dir'當做系統命令來執行。 # stdout=subprocess.PIPE,#接收正確的結果 # stderr=subprocess.PIPE #接收錯誤的結果 # ) # # print(res.stdout.read().decode('gbk'))#windows默認編碼gbk,按照gbk解碼讀取。 # print('stderr:'+res.stderr.read().decode('gbk'))#沒有錯誤結果,顯示空。 #黏包現象:1.發送端與接收端的數據不對等,接收端能接收的字節<發送的數據,接收到一部分數據,下次再執行命令接收的時候再從上一次 #開始。接收端能接收的字節>發送的數據,如果數據較小,nagle算法會將數據較小及時間間隔較短的數據黏包,合并到一起一同接收。 #如果沒有合理的拆包機制,則造成了無法拆分,出現黏包現象。 #tcp是字節流的形式。不能有空消息,如果有空消息,流中就會出現錯誤。造成無法發送。需要有空消息處理機制。 #udp是數據報形式,可以有空消息。 #tcp有黏包現象,udp沒有。udp是一個sendto對應一個recvfrom,一條消息對應一條消息,如果接收的字節數不夠,那其余的數據 #就會丟失。所以不可靠。不會黏包。 黏包?
#自己創建一個模塊,通過調用此模塊,省略一些編碼解碼的步驟。 # from socket import * # # class My_socket(socket): #以socket作為父類。 # def __init__(self,coding = 'utf-8'):#編碼為默認關鍵字參數。 # self.coding = coding # super(My_socket, self).__init__(type=SOCK_DGRAM) #沒有socket. # # def my_recv(self,num): #傳進來接收的字節數。如1024 # msg_r ,addr = self.recvfrom(num) # return msg_r.decode(self.coding),addr #返回編好碼的內容,按照傳進來的或默認的編碼方式。 # # def my_send(self,msg_s,addr): # return self.sendto(msg_s.encode(self.coding),addr)#返回編好碼的要發送的內容。 server: from 練習 import My_socketsk = My_socket() #實例化一個套接字對象。 sk.bind(('127.0.0.1',8090))#正常綁定while 1:msg_r , addr = sk.my_recv(1024) #調用類中接收方法。print(msg_r) #不需要做解碼動作。 msg_s = input('>>>')sk.my_send(msg_s,addr) #調用發送函數。不需要編碼。 sk.close()client:from 練習 import My_socketsk = My_socket()while 1:msg_s = input('>>>')sk.my_send(msg_s,('127.0.0.1',8090))msg_r ,addr = sk.my_recv(1024)print(msg_r)sk.close() 自定義socket?
#編碼流程: # TCP udp # s c s c # 創建套接字 創建套接字 # 綁定套接字 綁定套接字 # 監聽 # 等待接收 連接 # 發送/接收 先接收/再發送 # 關閉c套接字 # 關閉s套接字 關閉s套接字 關閉套接字 關閉套接字 TCP/UDP編碼流程?
轉載于:https://www.cnblogs.com/liujjpeipei/p/9147241.html
總結
- 上一篇: Oracle在开源Mission Con
- 下一篇: 第五人格人物死亡故事(《第五人格》官方网