基於tcp協議的登陸,文件上傳和下載

​ 【1】先登陸,登陸不成功循環登陸,直到成功。登陸成功後能夠選擇上傳或者下載,上傳有對應的文件,可選擇上傳哪一個;下載有對應的文件,可選擇下載哪一個
​ 【2】登陸,上傳,下載時最好設置狀態碼,客戶端和服務端約定好狀態碼,操做成功或者失敗後,發送對應的狀態碼。注意,每個操做要有惟一的狀態碼。
​ 好比: 登陸成功 100 登陸失敗 101python

​ 註冊成功 102 註冊失敗 103git

​ 上傳成功 104 上傳失敗 105編程

​ 下載成功 106 下載失敗 107json

​ 【3】也能夠用字典: dic = {'operate': 'login', 'result': res} res= True 或 False 代表要進行的操做,以及狀態。比較直觀
​ 【4】網絡之間進行數據傳遞,最經常使用的就是json模塊。傳送一個字典
​ 【5】編程儘可能少使用面向過程編程,多使用 函數 + 面向對象 編程
​ 【6】函數中都要用傳參的方式,傳入conn,sk等,不要用全局變量,便於文件拆分,進行進一步封裝。不用全局變量 ,由於未來文件拆分後,全局變量就不能用了。
​ 【7】輸入時,容易出錯的地方,要進行異常處理(進一步優化)網絡

#server
    import os
    import sys
    import json
    import struct
    import socket
    import hashlib

    def my_send(conn,dic): #用於發送要 被下載的文件的信息(字典{'filename': filename, 'filesize': filesize});可下載文件列表
        str_dic = json.dumps(dic)
        b_dic = str_dic.encode('utf-8')
        mlen = struct.pack('i', len(b_dic))
        conn.send(mlen)  # 4個字節 表示字典/列表轉成字節以後的長度
        conn.send(b_dic)  # 具體的字典數據

    def my_recv(conn): #用於接收將要上傳文件的信息(字典形式)
        msg_len = conn.recv(4)
        dic_len = struct.unpack('i', msg_len)[0]
        msg = conn.recv(dic_len).decode('utf-8')
        msg = json.loads(msg)
        return msg

    def download(conn):
        g = os.walk(r'D:\python22\day30\下載文件')
        file_lst = next(g)[2]  # ['11.jpg', '23.mp4', 'userinfo']
        my_send(conn,file_lst) #將文件列表發送到客戶端

        while 1:
            num = conn.recv(1024).decode('utf-8')  # 選擇要下載文件的序號
            if num.upper() == 'Q':break
            else:
                path = r'D:\python22\day30\下載文件'
                abs_path = os.path.join(path,file_lst[int(num) - 1])
                filename = os.path.basename(abs_path)
                filesize = os.path.getsize(abs_path)
                dic = {'filename': filename, 'filesize': filesize}
                my_send(conn,dic) #發送用戶選擇要下載文件的信息,是一個字典

                with open(abs_path, mode='rb') as f:
                    while filesize > 0:
                        content = f.read(1024)
                        filesize -= len(content)
                        conn.send(content)

    def upload(conn):
        while 1:
            msg = my_recv(conn)
            if msg['filename'] == None:break
            else:
                with open(msg['filename'],'wb') as f:
                    while msg['filesize'] > 0:
                        content = conn.recv(1024)
                        msg['filesize'] -= len(content)
                        f.write(content)
                conn.send('上傳成功'.encode('utf-8'))

    def get_md5(username,password):
        md5 = hashlib.md5(username.encode('utf-8'))
        md5.update(password.encode('utf-8'))
        return md5.hexdigest()

    def login(conn):
        flag = True#用於跳出外層循環
        while flag:   #注意跳出多級循環問題
            msg = my_recv(conn)
            with open('userinfo') as f:
                for line in f:
                    name, pwd = line.strip().split('|')
                    if name == msg['username'] and pwd == get_md5(name, msg['password']):
                        res, flag = True, False
                        break #跳出本級循環
                else:
                    res = False
                dic = {'operate': 'login', 'result': res} #狀態碼
                my_send(conn, dic)
    
    #主邏輯
    sk = socket.socket()
    sk.bind(('127.0.0.1',9002))
    sk.listen()

    conn,_ =sk.accept()
    login(conn)
    opt_dic = my_recv(conn)
    if hasattr(sys.modules[__name__],opt_dic['operate']): # __name__是變量名,以腳本運行時,對應的值爲'__main__'。可是被當作模塊導入時,名字爲模塊名。因此最好用__name__
        getattr(sys.modules[__name__],opt_dic['operate'])(conn)

    conn.close()
    sk.close()
    
#client
    import os
    import sys
    import json
    import struct
    import socket
    def download(sk):  # 下載
        opt_dic = {'operate':'download'}
        my_send(sk,opt_dic) #將要進行的操做發送到服務端

        file_lst = my_recv(sk) #接收到來自服務端的文件列表
        while 1:
            for index, file in enumerate(file_lst, 1):
                print(index,file)
            num = input('請輸入要下載文件的序號(退出請按Q):').strip()
            if num.upper() == 'Q':
                sk.send(num.encode('utf-8'))  # 發送q或Q
                break
            elif num.isdigit() and 0 < int(num) <= len(file_lst):
                sk.send(num.encode('utf-8'))  # 發送要下載文件的序號
                msg = my_recv(sk) #接收要下載文件的信息,是一個字典
                with open(msg['filename'], 'wb') as f:
                    while msg['filesize'] > 0:
                        content = sk.recv(1024)
                        msg['filesize'] -= len(content)
                        f.write(content)
                print('下載成功')
            else:
                print('輸入有誤')

    def upload(sk):
        opt_dic = {'operate': 'upload'}
        my_send(sk, opt_dic)

        g = os.walk(r'D:\python22\day30\上傳文件')
        file_lst = next(g)[2]  # ['11.jpg', '23.mp4', 'userinfo']
        while 1:
            for index, file in enumerate(file_lst, 1):
                print(index, file)
            num = input('請輸入要上傳文件的序號(退出請按Q):').strip()
            if num.upper() == 'Q':
                dic = {'filename': None, 'filesize': None}
                my_send(sk, dic)
                break
            elif num.isdigit() and 0 < int(num) <= len(file_lst):
                path = r'D:\python22\day30\上傳文件'
                abs_path = os.path.join(path, file_lst[int(num) - 1])
                filename = os.path.basename(abs_path)
                filesize = os.path.getsize(abs_path)
                dic = {'filename': filename, 'filesize': filesize}
                my_send(sk,dic)

                with open(abs_path, mode='rb') as f:
                    while filesize > 0:
                        content = f.read(1024)
                        filesize -= len(content)
                        sk.send(content)
                msg = sk.recv(1024).decode('utf-8')
                print(msg)

    def my_recv(sk):     # 接收
        msg_len = sk.recv(4)
        dic_len = struct.unpack('i', msg_len)[0]
        msg = sk.recv(dic_len).decode('utf-8')
        msg = json.loads(msg)
        return msg

    def my_send(sk,dic):   # 發送
        str_dic = json.dumps(dic)
        b_dic = str_dic.encode('utf-8')
        mlen = struct.pack('i', len(b_dic))
        sk.send(mlen)  # 4個字節 表示字典轉成字節以後的長度
        sk.send(b_dic)  # 具體的字典數據

    def login(sk):
        while True: #alex|aee949757a2e698417463d47acac93df
            usr = input('用戶名:').strip() #alex
            pwd = input('密 碼 :').strip() #3714
            dic = {'username': usr, 'password': pwd}
            my_send(sk, dic)
            ret = my_recv(sk)  #dic = {'operate': 'login', 'result': res} res=True 或 False
            if ret['operate'] == 'login' and ret['result']:
                print('登陸成功')
                break
            else:
                print('登陸失敗')

    #主邏輯
    sk = socket.socket()
    sk.connect(('127.0.0.1',9002))

    login(sk)   # 登陸
    opt_lst = ['upload','download']
    for index,opt in enumerate(opt_lst,1):
        print(index,opt)
    num = int(input('請選擇您要操做的序號 :'))
    getattr(sys.modules[__name__],opt_lst[num-1])(sk)

    sk.close()
相關文章
相關標籤/搜索