python socket实现文件传输(防粘包)
1.文件傳輸?shù)囊c(diǎn):
采用iterator(迭代器對(duì)象)迭代讀取,提高讀取以及存取效率;
通過for line in file_handles逐行conn.send();
2.socket粘包問題:
[出現(xiàn)原因]:A.TCP協(xié)議為了提高傳輸效率,發(fā)送方往往需要收集定量的數(shù)據(jù)才會(huì)封裝給底層并發(fā)送,若出現(xiàn)連續(xù)send(data),TCP會(huì)把該數(shù)據(jù)進(jìn)行整合(直到裝滿數(shù)據(jù)緩沖區(qū)),這樣就造成了粘包數(shù)據(jù);B.接收方接收方的粘包是由于接收用戶相關(guān)進(jìn)程不及時(shí)接收數(shù)據(jù),從而導(dǎo)致粘包問題,這是因?yàn)榻邮辗较劝呀邮盏降臄?shù)據(jù)放在系統(tǒng)接受緩沖區(qū),用戶進(jìn)程從該緩沖區(qū)取定量的數(shù)據(jù),但若下一包數(shù)據(jù)到達(dá)前,緩沖區(qū)的數(shù)據(jù)沒有及時(shí)的被用戶進(jìn)程取走,則下一包數(shù)據(jù)與前一包部分?jǐn)?shù)據(jù)在系統(tǒng)緩沖區(qū),就可能導(dǎo)致用戶設(shè)定的進(jìn)程緩沖區(qū)從系統(tǒng)緩沖區(qū)取走兩個(gè)包的部分?jǐn)?shù)據(jù),從而導(dǎo)致粘包
[解決辦法]:A 發(fā)送方在send()之前,先向接收方發(fā)送數(shù)據(jù)總量大小,并通過雙端確認(rèn),server端發(fā)送數(shù)據(jù)包,然后接收方通過按數(shù)據(jù)量大小循環(huán)設(shè)立緩沖區(qū)接收數(shù)據(jù);;B: TCP提供了PUSH(強(qiáng)制數(shù)據(jù)立即傳送)操作,但影響性能;C. 周全并且高效的處理粘包請(qǐng)參考:點(diǎn)擊這里
3.code
server.py
''' 遇到問題沒人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! ''' __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+=1print('客戶端%s已連接上!' % count)while 1:cmd = conn.recv(1024)order,filename1 = str(cmd.decode()).split()if os.path.isfile(filename1):print('命令:%s\n待發(fā)送的文件名:%s' % (order,filename1))#發(fā)送文件的大小及文件名post_server = filename1+' '+str(os.stat(filename1).st_size)conn.send(post_server.encode(encoding='utf-8'))#發(fā)送文件確認(rèn)號(hào)ACK = conn.recv(1024)#16進(jìn)制摘要m = hashlib.md5()with open(filename1,'rb') as f:for line in f:m.update(line)conn.send(line)print('%s發(fā)送完畢!' % filename1)#此處循環(huán)完成之后,繼續(xù)send(),可能出現(xiàn)socket粘包conn.send(m.hexdigest().encode())continueelse:ERROR = '錯(cuò)誤!請(qǐng)檢查文件名!'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('連接服務(wù)器成功!') while 1:print('請(qǐng)輸入請(qǐng)求信號(hào)及請(qǐng)求內(nèi)容\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)continueelse:file_len = int(file_size)print('待傳輸文件大小:%s' % file_len)temp = 0client.send('已發(fā)送!'.encode(encoding='utf-8'))#MD5對(duì)象m_client = hashlib.md5()while temp<file_len:with open('another.txt','wb') as f:#避免服務(wù)器連續(xù)send出現(xiàn)粘包if temp+1024>file_len:last_len = file_len - tempdata_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實(shí)際接收文件大小:%s' % temp)#接收16進(jìn)制摘要md5_info = client.recv(1024)if md5_info.decode() == m_client.hexdigest():print('MD5驗(yàn)證成功!') client.close() 與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的python socket实现文件传输(防粘包)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python-各种结构解析以及生成器(列
- 下一篇: python中super的用法实例解析