@Author:Runsen
@Date:2020/5/29
作者介紹:Runsen目前大三下學期,專業化學工程與工藝,大學沉迷日語,Python, Java和一系列數據分析軟件。導致翹課嚴重,專業排名中下。.在大學60%的時間,都在CSDN。決定今天比昨天要更加努力。
我預計寫零基礎學Python寫到一百篇,這是第六十篇,還剩四十篇
實現的效果如下的Gif所示,就是網絡通信Socket模塊實現文件傳輸。
服務端
首先需要獲取本機ip,這裏服務端採用多線程的方法,就是定義一個函數,然後用threading創建任務。客戶端連接成功,接收客戶端的請求信息,就是下載的文件名。所以需要判斷,有輸出文件字節數。然後在問用戶是不是要下載,得到信息就使用 while True: 讀文件的內容,再一個send。就是這麼簡單,看代碼是不是就是這麼回事。
import socket
import os
import threading
# 獲取本機ip
def get_host_ip():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))
ip = s.getsockname()[0]
finally:
s.close()
return ip
# 處理客戶端請求下載文件的操作(從主線程提出來的代碼)
def deal_client_request(ip_port, service_client_socket):
# 連接成功後,輸出“客戶端連接成功”和客戶端的ip和端口
print("客戶端連接成功", ip_port)
# 接收客戶端的請求信息【recv】
file_name = service_client_socket.recv(1024)
# 解碼
file_name_data = file_name.decode("utf-8")
# 判斷文件是否存在
if os.path.exists(file_name_data):
#輸出文件字節數
fsize = os.path.getsize(file_name_data)
#轉化爲兆單位
fmb = fsize/float(1024*1024)
#要傳輸的文件信息
senddata = "文件名:%s 文件大小:%.2fMB"%(file_name_data,fmb)
#發送和打印文件信息【send】
service_client_socket.send(senddata.encode("utf-8"))
print("請求文件名:%s 文件大小:%.2f MB"%(file_name_data,fmb))
#接受客戶是否需要下載【recv】
options = service_client_socket.recv(1024)
if options.decode("utf-8") == "y":
# 打開文件
with open(file_name_data, "rb") as f:
# 計算總數據包數目
nums = fsize/1024
# 當前傳輸的數據包數目
cnum = 0
while True:
file_data = f.read(1024)
cnum = cnum + 1
#progress = cnum/nums*100
#print("當前已下載:%.2f%%"%progress,end = "\r")
if file_data:
# 只要讀取到數據,就向客戶端進行發送【send】
service_client_socket.send(file_data)
# 數據讀完,退出循環
else:
print("請求的文件數據發送完成")
break
else:
print("下載取消!")
else:
print("下載的文件不存在!")
# 關閉服務當前客戶端的套接字【close】
service_client_socket.close()
if __name__ == '__main__':
# 獲取本機ip
print("TCP文件傳輸服務器,本機IP:" + get_host_ip())
# 把工作目錄切換到data目錄下
os.chdir("./data")
# 創建套接字【socket】
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 綁定端口號【bind】
tcp_server_socket.bind(("", 3356))
# 設置監聽,將主動套接字變爲被動套接字【listen】
tcp_server_socket.listen(128)
# 循環調用【accept】,可以支持多個客戶端同時連接,和多個客戶端同時下載文件
while True:
service_client_socket, ip_port = tcp_server_socket.accept()
# 連接成功後打印套接字號
#print(id(service_client_socket))
# 創建子線程
sub_thread = threading.Thread(target=deal_client_request, args=(ip_port, service_client_socket))
# 啓動子線程
sub_thread.start()
客戶端
客戶端更簡單,連接服務端,發送下載文件的請求,定義一個寫入的文件夾,就是小兒科東西。不寫了,看代碼。
# -*- coding:utf-8 -*-
# 多任務文件下載器客戶端
import socket
import os
if __name__ == '__main__':
# 創建套接字【socket】
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 和服務端連接【connect】
server_ip = input("輸入服務器IP:")
tcp_client_socket.connect((server_ip, 3356))
# 發送下載文件的請求
file_name = input("請輸入要下載的文件名:")
# 編碼
file_name_data = file_name.encode("utf-8")
# 發送文件下載請求數據【send】
tcp_client_socket.send(file_name_data)
# 接收要下載的文件信息【recv】
file_info = tcp_client_socket.recv(1024)
# 文件信息解碼
info_decode = file_info.decode("utf-8")
print(info_decode)
#獲取文件大小
fileszie = float(info_decode.split(':')[2].split('MB')[0])
fileszie2 = fileszie*1024
# 是否下載?輸入y 確認 輸入q 取消
opts = input("是否下載?(y 確認 q 取消)")
if opts == 'q':
print("下載取消!程序退出")
else:
print("正在下載 >>>>>>")
#向服務器確認正在下載【send】
tcp_client_socket.send(b'y')
recvpath = "./receive/"
if not os.path.exists(recvpath):
os.mkdir(recvpath)
# 把數據寫入到文件裏
with open(recvpath + file_name, "wb") as file:
#目前接收到的數據包數目
cnum = 0
while True:
# 循環接收文件數據【recv】
file_data = tcp_client_socket.recv(1024)
# 接收到數據
if file_data:
# 寫入數據
file.write(file_data)
cnum = cnum+1
#progress =cnum/fileszie2*100
#print("當前已下載:%.2f%%"%progress,end = "\r")
# 接收完成
else:
print("下載結束!")
break
# 關閉套接字【close】
tcp_client_socket.close()