python socket實現文件傳輸(防粘包)


1.文件傳輸的要點:

  采用iterator(迭代器對象)迭代讀取,提高讀取以及存取效率;

  通過for line in file_handles逐行conn.send();

2.socket粘包問題:

  [出現原因]:A.TCP協議為了提高傳輸效率,發送方往往需要收集定量的數據才會封裝給底層並發送,若出現連續send(data),TCP會把該數據進行整合(直到裝滿數據緩沖區),這樣就造成了粘包數據;B.接收方接收方的粘包是由於接收用戶相關進程不及時接收數據,從而導致粘包問題,這是因為接收方先把接收到的數據放在系統接受緩沖區,用戶進程從該緩沖區取定量的數據,但若下一包數據到達前,緩沖區的數據沒有及時的被用戶進程取走,則下一包數據與前一包部分數據在系統緩沖區,就可能導致用戶設定的進程緩沖區從系統緩沖區取走兩個包的部分數據,從而導致粘包

  [解決辦法]:A 發送方在send()之前,先向接收方發送數據總量大小,並通過雙端確認,server端發送數據包,然后接收方通過按數據量大小循環設立緩沖區接收數據;;B: TCP提供了PUSH(強制數據立即傳送)操作,但影響性能;C. 周全並且高效的處理粘包請參考:點擊這里

3.code 

server.py

__author__ = 'kisunny'
import socket,os,hashlib
server = socket.socket() server.bind(('localhost',6669)) server.listen(2) count = 0 while 1: conn,addr = server.accept() count+=1 print('客戶端%s已連接上!' % count) while 1: cmd = conn.recv(1024) order,filename1 = str(cmd.decode()).split() if os.path.isfile(filename1): print('命令:%s\n待發送的文件名:%s' % (order,filename1)) #發送文件的大小及文件名 post_server = filename1+' '+str(os.stat(filename1).st_size) conn.send(post_server.encode(encoding='utf-8')) #發送文件確認號 ACK = conn.recv(1024) #16進制摘要 m = hashlib.md5() with open(filename1,'rb') as f: for line in f: m.update(line) conn.send(line) print('%s發送完畢!' % filename1) #此處循環完成之后,繼續send(),可能出現socket粘包  conn.send(m.hexdigest().encode()) continue else: ERROR = '錯誤!請檢查文件名!' conn.send(ERROR.encode(encoding='utf-8')) server.close()

client.py

__author__ = 'kisunny'
import socket,hashlib
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('localhost',6669)) print('連接服務器成功!') while 1: print('請輸入請求信號及請求內容\n格式:response filename') cmd_order = input('>>:').strip() client.send(cmd_order.encode('utf-8')) cls_msg = client.recv(1024) try: filename2,file_size = str(cls_msg.decode()).split() except ValueError as e: print(e) continue else: file_len = int(file_size) print('待傳輸文件大小:%s' % file_len) temp = 0 client.send('已發送!'.encode(encoding='utf-8')) #MD5對象 m_client = hashlib.md5() while temp<file_len: with open('another.txt','wb') as f: #避免服務器連續send出現粘包 if temp+1024>file_len: last_len = file_len - temp data_temp = client.recv(last_len) else: data_temp = client.recv(1024) f.write(data_temp) m_client.update(data_temp) temp += len(data_temp) print('接收文件完畢!\n實際接收文件大小:%s' % temp) #接收16進制摘要 md5_info = client.recv(1024) if md5_info.decode() == m_client.hexdigest(): print('MD5驗證成功!') client.close()

功能未完善,僅做DEMO參考

哈哈,好好學習,加油!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM