【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()