1. 程式人生 > >檔案傳送

檔案傳送

簡單版

服務端

import socket
import subprocess
import struct
import json
import os

share_dir = r'F:\project\book\chapter6\檔案傳輸\簡單版本\server\share'

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # (如果機器中存在,重新用埠)應對端口占用報錯情況

phone.bind(("127.0.0.1", 9909))   # 127.0.0.1本地地址,埠範圍0-65535:其中0-1024給作業系統使用

phone.listen(5)   # 5代表最大掛起連線數

print("starting...")
while True:  # 迴圈連結
    conn, client = phone.accept()  # conn套接字物件

    while True:    # 通訊迴圈
        try:
            # 1、接收命令  (命令:執行系統命令)
            res = conn.recv(8096)  # b'get a.txt

            # 2、解析命令,提取相應的命令引數
            cmds = res.decode("utf-8").split()
            filename = cmds[1]

            # 3、以讀的方式開啟檔案,讀取檔案內容,傳送給客戶端

            # 第一步:製作固定長度的報頭(import struct)
            header_dic = {
                "filename": filename,
                "md5": "xxdxxx",
                "file_size": os.path.getsize(r"%s/%s" % (share_dir, filename))
            }
            header_json = json.dumps(header_dic)

            header_bytes = header_json.encode("utf-8")

            # 第二步:先發送報頭的長度
            conn.send(struct.pack("i", len(header_bytes)))

            # 第三步:再發報頭
            conn.send(header_bytes)

            # 第四步:再發送真實的資料
            with open("%s/%s" % (share_dir, filename), "rb")as f:
                # conn.send(f.read())   # 如果檔案太大,會佔滿記憶體
                for line in f:
                    conn.send(line)

        except ConnectionRefusedError:
            break

    conn.close()

phone.close()

 客戶端

import socket
import struct
import json

download_dir = r"F:\project\book\chapter6\檔案傳輸\簡單版本\client\download"

phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

phone.connect(("127.0.0.1", 9909))  # phone相當於服務端的conn

while True:
    # 1、發命令
    cmd = input(">> ").strip()  # get a.txt
    if not cmd:
        continue
    phone.send(cmd.encode("utf-8"))

    # 2、以寫的方式開啟一個新檔案,接收服務端發來的檔案的內容寫入客戶端的新檔案中
    # 第一步:先收報頭的長度
    header = phone.recv(4)
    header_size = struct.unpack("i", header)[0]

    # 第二步:再接收報頭資訊
    header_bytes = phone.recv(header_size)

    # 第三步:從報頭中解析出對真實資料的描述資訊
    header_json = header_bytes.decode("utf-8")
    header_dic = json.loads(header_json)
    print(header_dic)
    file_size = header_dic["file_size"]
    filename = header_dic["filename"]

    # 第四步:接受真實的資料
    with open("%s/%s" % (download_dir, filename), "wb")as f:
        recv_size = 0
        while recv_size < file_size:
            line = phone.recv(1024)
            f.write(line)
            recv_size += len(line)
            print("總大小:%s  已下載大小:%s" % (file_size, recv_size))

phone.close()

  


函式版

服務端

import socket
import subprocess
import struct
import json
import os

share_dir = r'F:\project\book\chapter6\檔案傳輸\函式版本\server\share'


def get(conn, cmds):
    filename = cmds[1]
    # 3、以讀的方式開啟檔案,讀取檔案內容,傳送給客戶端
    # 第一步:製作固定長度的報頭(import struct)
    header_dic = {
        "filename": filename,
        "md5": "xxdxxx",
        "file_size": os.path.getsize(r"%s/%s" % (share_dir, filename))
    }
    header_json = json.dumps(header_dic)
    header_bytes = header_json.encode("utf-8")

    # 第二步:先發送報頭的長度
    conn.send(struct.pack("i", len(header_bytes)))

    # 第三步:再發報頭
    conn.send(header_bytes)

    # 第四步:再發送真實的資料
    with open("%s/%s" % (share_dir, filename), "rb")as f:
        # conn.send(f.read())   # 如果檔案太大,會佔滿記憶體
        for line in f:
            conn.send(line)


def put(conn, cmds):
    pass


def run():
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # (如果機器中存在,重新用埠)應對端口占用報錯情況
    phone.bind(("127.0.0.1", 9909))   # 127.0.0.1本地地址,埠範圍0-65535:其中0-1024給作業系統使用
    phone.listen(5)   # 5代表最大掛起連線數

    print("starting...")
    while True:  # 迴圈連結
        conn, client = phone.accept()  # conn套接字物件

        while True:    # 通訊迴圈
            try:
                # 1、接收命令  (命令:執行系統命令)
                res = conn.recv(8096)  # b'get a.txt

                # 2、解析命令,提取相應的命令引數
                cmds = res.decode("utf-8").split()
                if cmds[0] == "get":
                    get(conn, cmds)
                elif cmds[0] == "put":
                    put(conn, cmds)
            except ConnectionRefusedError:
                break

        conn.close()

    phone.close()


if __name__ == "__main__":   #如果是執行當前檔案的時候,這個條件成立,就執行。如果當前檔案被其他檔案當成模組匯入的時候,這個條件是不成立的,裡面的程式碼是不執行的
    run()

 客戶端

import socket
import struct
import json

download_dir = r"F:\project\book\chapter6\檔案傳輸\函式版本\client\download"


def get(phone, cmds):
    # 2、以寫的方式開啟一個新檔案,接收服務端發來的檔案的內容寫入客戶端的新檔案中
    # 第一步:先收報頭的長度
    header = phone.recv(4)
    header_size = struct.unpack("i", header)[0]

    # 第二步:再接收報頭資訊
    header_bytes = phone.recv(header_size)

    # 第三步:從報頭中解析出對真實資料的描述資訊
    header_json = header_bytes.decode("utf-8")
    header_dic = json.loads(header_json)
    print(header_dic)
    file_size = header_dic["file_size"]
    filename = header_dic["filename"]

    # 第四步:接受真實的資料
    with open("%s/%s" % (download_dir, filename), "wb")as f:
        recv_size = 0
        while recv_size < file_size:
            line = phone.recv(1024)
            f.write(line)
            recv_size += len(line)
            print("總大小:%s  已下載大小:%s" % (file_size, recv_size))


def put(phone, cmds):
    pass


def run():
    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    phone.connect(("127.0.0.1", 9909))  # phone相當於服務端的conn

    while True:
        # 1、發命令
        inp = input(">> ").strip()  # get a.txt
        if not inp:
            continue
        phone.send(inp.encode("utf-8"))
        cmds = inp.split()  # ["get","a.txt"]
        if cmds[0] == "get":
            get(phone, cmds)
        elif cmds[0] == "put":
            put(phone, cmds)
    phone.close()


if __name__ == "__main__":   # 如果是執行當前檔案的時候,這個條件成立,就執行。如果當前檔案被其他檔案當成模組匯入的時候,這個條件是不成立的,裡面的程式碼是不執行的
    run()