在這裏我實現的是客戶端上傳文件,服務器接收文件,如果要實現客戶端從服務器上下載文件的話,直接將代碼反過來即可。廢話不多說,下面直接上代碼吧。
下面是服務器端的代碼
import socket
import struct
import json
sk = socket.socket()
sk.bind(('127.0.0.1', 8888)) # 綁定ip地址和端口
sk.listen() # 開啓監聽
buffer = 1024 # 緩衝區大小,這裏好像因爲windows的系統的原因,這個接收的緩衝區不能太大
conn, addr = sk.accept()
# 先接收報頭的長度
head_len = conn.recv(4)
head_len = struct.unpack('i', head_len)[0] # 將報頭長度解包出來
# 再接收報頭
json_head = conn.recv(head_len).decode('utf-8') # 拿到的是bytes類型的數據,要進行轉碼
head = json.loads(json_head) # 拿到原本的報頭
file_size = head['filesize']
with open(head['filename'], 'ab') as f:
print(file_size)
while file_size:
if file_size >= buffer: # 判斷剩餘文件的大小是否超過buffer
content = conn.recv(buffer)
f.write(content)
file_size -= buffer
else:
content = conn.recv(file_size)
f.write(content)
file_size = 0
break
conn.close()
sk.close()
下面是客戶端的代碼
import socket
import os
import json
import struct
sk = socket.socket()
sk.connect(('127.0.0.1', 8888)) # 與服務器建立連接
buffer = 1024
# 定製我們的報頭,這裏的報頭不是唯一的,你可以根據你的想法去更改
head = {'filepath': r'你的文件路徑',
'filename': r'你要傳的文件名',
'filesize': None}
file_path = os.path.join(head['filepath'], head['filename'])
# 計算文件的大小
filesize = os.path.getsize(os.path.join(head['filepath'], head['filename']))
head['filesize'] = filesize
json_head = json.dumps(head) # 利用json將字典轉成字符串
bytes_head = json_head.encode('utf-8') # 字符串轉bytes
# 計算head長度
head_len = len(bytes_head) # 報頭的長度
# 利用struct將int類型的數據打包成4個字節的byte,所以服務器端接受這個長度的時候可以固定緩衝區大小爲4
pack_len = struct.pack('i', head_len)
# 先將報頭長度發出去
sk.send(pack_len)
# 再發送bytes類型的報頭
sk.send(bytes_head)
with open(file_path, 'rb') as f:
while filesize:
print(filesize)
if filesize >= buffer:
content = f.read(buffer) # 每次讀取buffer字節大小內容
filesize -= buffer
sk.send(content) # 發送讀取的內容
else:
content = f.read(filesize)
sk.send(content)
filesize = 0
break
sk.close()
在這個上傳、下載文件的實驗中,發現了一個現象,就是buffer基本不能超過1024字節大小,,如果超過1024的大小就會報錯,這可能與windows操作系統有關,可能是由於讀寫不同步造成的。