Python利用Socket實現檔案上傳和下載

NO IMAGE

第一次寫Socket,大家見笑了。註釋都很清楚,不多說了。

值得一提的是中間碰到過一個bug是:

unpack requires a bytes object of length

百度了半天,某些博主扯了好多都沒說清楚

其實就是用struct打包了以後字串流的大小會固定,但是你接收的大小跟你指定的編碼方式不一樣

我這次出錯是因為在發壓縮包之前先發了個串,然後伺服器接到的不是壓縮的串所以出錯了,所以unpack接收的必須是你pack後的串,不然會出錯

OK,以下是伺服器端的程式碼:

#coding:utf-8
'''
@DateTime: 	2017-09-24 12:25:13
@Version: 	1.0
@Author: 	Unname_Max
'''
import threading
import socket
import time
import operator
import os
import struct
#實現下載功能
def download(connect):
#獲取檔案目錄
files = os.listdir()
#用於傳輸檔案目錄的字串
liststr = ''
#將所有檔名傳入字串中
for i in files:
liststr  = i   '\n'
#如果檔案列表為空,將不繼續執行下載任務
if operator.eq(liststr,''): 
connect.send(''.encode())
#如果檔案列表不為空,開始下載任務
else :
#向客戶端傳送檔案列表
connect.send(liststr.encode())
while  True:
#獲取客戶端要下載的檔名,如果不存在就繼續輸入
filename = connect.recv(100).decode()
if filename not in files:
connect.send('檔案不存在!'.encode())
else:
connect.send('開始檔案傳輸!'.encode())
break
#將檔案資訊打包傳送給客服端
fhead = struct.pack('128sI',filename.encode(),os.stat(filename).st_size)
connect.send(fhead)
#傳送檔案資訊
with open(filename,'rb') as f:
while True:
filedata = f.read(1024)
if not filedata:
break
connect.send(filedata)
#儲存到日誌中
print ('%s\n下載檔案:\n%s\n成功\n\n'%(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())),filename))
os.chdir('..')
with open('data.log','a') as f:
f.write('%s\n下載檔案:\n%s\n成功\n\n'%(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())),filename))
os.chdir('files')
#實現上傳功能
def upload(connect):
FILEINFO_SIZE = struct.calcsize('128sI')
try:
#獲取打包好的檔案資訊,並解包
fhead = connect.recv(FILEINFO_SIZE)
filename , filesize = struct.unpack('128sI',fhead)
filename = filename.decode().strip('\00')
#檔名必須去掉\00,否則會報錯,此處為接收檔案
with open ('newnew_'  filename,'wb') as f:
ressize = filesize
while True:
if ressize>1024:
filedata = connect.recv(1024)
else:
filedata = connect.recv(ressize)
f.write(filedata)
break
if not filedata:
break
f.write(filedata)
ressize = ressize - len(filedata)
if ressize <0:
break
#儲存到日誌
print ('%s\n傳輸檔案:\n%s\n成功\n\n'%(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())),filename))
os.chdir('..')
with open('data.log','a') as f:
f.write('%s\n傳輸檔案:\n%s\n成功\n\n'%(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())),filename))
os.chdir('files')
except Exception as e:
print ('%s\n傳輸檔案:\n%s\n成功\n\n'%(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())),filename))
os.chdir('..')
with open('data.log','a') as f:
f.write('%s\n傳輸檔案:\n%s\n失敗\n\n'%(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())),filename))
os.chdir('files')
def handle(connect,address):
print ('%s:%s is connectting...'%(address))
while True:
order = connect.recv(100).decode()
if operator.eq(order,'1'):
download(connect)
elif operator.eq(order,'2'):
upload(connect)
elif operator.eq(order,'3'):
connect.close()
break
connect.send('''
1、 下載檔案
2、 上傳檔案
3、 退出
'''.encode())
if __name__ == '__main__':
if not os.path.exists('files'):
os.mkdir('files')
#工作目錄換到files資料夾
os.chdir('files')
#建立socket連結,並監聽8002埠
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(('',8002))
sock.listen(100)
while True:
connect,address = sock.accept()
connect.send('''歡迎使用檔案管理伺服器,您已經成功連線,請選擇您要選用的選項:
1、 下載檔案
2、 上傳檔案
3、 退出
'''.encode())
t = threading.Thread(target = handle,args = (connect,address))
t.setDaemon(True)
t.start()
sock.close()

以下是客戶端的程式碼:

#coding:utf-8
'''
@DateTime: 	2017-09-24 14:26:31
@Version: 	1.0
@Author: 	Unname_Max
'''
import socket
import struct
import operator
import time
import os
#實現下載功能
def download(sock):
#從服務端接收檔案列表
filelist = sock.recv(1024).decode()
if operator.eq(filelist,''):
print ('沒有可以下載的檔案')
print (filelist)
#從使用者中輸入接收檔名,併傳送給服務端
filename  = input('請輸入要下載的檔名:\n')
sock.send(filename.encode())
#獲取包大小,並解壓
FILEINFO_SIZE = struct.calcsize('128sI')
try:
fhead = sock.recv(1024)
fhead = sock.recv(FILEINFO_SIZE)
filename , filesize = struct.unpack('128sI',fhead)
#接收檔案
with open ('new_' filename.decode().strip('\00'),'wb') as f:
ressize = filesize
while True:
if ressize>1024:
filedata = sock.recv(1024)
else:
filedata = sock.recv(ressize)
f.write(filedata)
break
if not filedata:
break
f.write(filedata)
ressize = ressize - len(filedata)
if ressize <0:
break
print ('檔案傳輸成功!')
except Exception as e:
print (e)
print ('檔案傳輸失敗!')
#實現上傳功能
def upload(sock):
#獲取檔案路徑,並將檔案資訊打包傳送給服務端
path = input('請輸入要上傳的檔案路徑\n')
filename = input('請輸入檔名\n')
fhead = struct.pack('128sI',filename.encode(),os.stat(filename).st_size)
sock.send(fhead)
#傳送檔案
with open (path,'rb') as f:
while True:
filedata = f.read(1024)
if not filedata:
break
sock.send(filedata)
print('檔案傳輸結束')
def  handle(sock):
while True:
order = input()
if operator.eq(order,'1'):
sock.send(order.encode())
download(sock)
elif operator.eq(order,'2'):
sock.send(order.encode())
upload(sock)
elif operator.eq(order,'3'):
print('正在關閉連線...')
time.sleep(0.5)
sock.send(order.encode())
break
else:
print('命令錯誤,請重新輸入!')
continue
line = sock.recv(1024)
print(line.decode())
if __name__ == '__main__':
#建立socket並連線8002埠
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect(('127.0.0.1',8002))
line = sock.recv(1024)
print(line.decode())
handle(sock)
sock.close()