client
import os
import json
import struct
import socket
import sys
def send_dic(sk1, dic, protocol=False):
bytes_d = json.dumps(dic).encode('utf-8') # json.dumps()将python值转化json格式的数据字符串
if protocol: # true按你找协议执行send,false直接发送不要协议
len_b = len(bytes_d)
len_dic = struct.pack('i', len_b) # pack按照‘i‘格式把数据转化为字符串
sk1.send(len_dic)
else:
pass
sk1.send(bytes_d)
def recv_dic(sk1):
str_dic = sk1.recv(1024).decode('utf-8')
res_dic = json.loads(str_dic) # json.loads()把json转换python的数据类型
return res_dic
def get_user(opt='login'):
d = {}
a = 0
while d == {} or a == 0:
usr = input('用户名:').strip() # 出去左右两边空格
pwd = input('密码:').strip()
if usr and pwd and opt == 'login':
d = {'username': usr, 'password': pwd, 'operate': opt}
a = 1
elif usr and pwd and opt == 'register':
pwd2 = input('密码确认:').strip()
if pwd == pwd2:
d = {'username': usr, 'password': pwd, 'operate': opt}
a = 1
else:
print("两次密码不一致!")
a = 1
pass
else:
pass
return d
def login(sk1): # 登录
d = get_user()
if d: send_dic(sk1, d)
res_dic = recv_dic(sk1)
if res_dic['operate'] == 'login' and res_dic['flag']:
print('登录成功')
return True
else:
print('登录失败')
return False
def register(sk1): # 注册
d = get_user('register')
if d: send_dic(sk1, d)
res_dic = recv_dic(sk1)
print(res_dic)
if res_dic['operate'] == 'register' and res_dic['flag']:
print('注册成功')
return True
else:
print('注册失败')
return False
def upload(sk1):
# 输入路径
path = input('请输入要上传的文件路径:')
if os.path.isfile(path): # 判断是否是文件是则返回为真
filename = os.path.basename(path) # 返回文件名
filesize = os.path.getsize(path)
dic = {'filename': filename, 'filesize': filesize, 'operate': 'upload'}
send_dic(sk1, dic, True) # true表示这里使用自定义协议进行字典的传递
with open(path, 'rb') as f: # 文件读取,rb读二进制文件指针会放在文件开头
while filesize > 0:
content = f.read(1024)
sk1.send(content)
filesize -= len(content)
else:
pass
def download(sk1):
# 输入路径
path1 = input('请输入要下载的文件全名称:')
path = "D:\FTP1\local\\" + path1
if os.path.isfile(path): # 判断是否是文件是则返回为真
filename = os.path.basename(path) # 返回文件名
filesize = os.path.getsize(path)
dic = {'filename': filename, 'filesize': filesize, 'operate': 'download'}
send_dic(sk1, dic, True) # true表示这里使用自定义协议进行字典的传递
with open(path, 'rb') as f: # 文件读取,rb读二进制文件且指针会放在文件开头
while filesize > 0:
content = f.read(1024)
sk1.send(content)
filesize -= len(content)
else:
pass
def quit(sk1):
dic = {'operate': 'quit'}
send_dic(sk1, dic, True)
print("退出成功!")
sys.exit()
def choose_opt(opt_lst1):
num = '0'
for index, opt in enumerate(opt_lst1, 1):
print(index, opt[0])
while num != '1' and num != '2':
num = str(input('请输入要选择的操作序号 : '))
if num != '1' and num != '2':
print("输入错误!")
num1 = int(num)
func = opt_lst1[num1 - 1][1] # func = login / register
return func
def choose_opt1(opt_lst1):
num = '0'
for index, opt in enumerate(opt_lst1, 1):
print(index, opt[0])
while num != '1' and num != '2' and num != '3':
num = str(input('请输入要选择的操作序号 : '))
if num != '1' and num != '2' and num != '3':
print("输入错误!")
else:
pass
num1 = int(num)
func = opt_lst1[num1 - 1][1] # func = login / register
return func
while True:
sk = socket.socket() # 生成socket连接对象
sk.connect(('127.0.0.1', 9006))
# 选择登录/注册
opt_lst = [('登录', login), ('注册', register)]
func = choose_opt(opt_lst)
res = func(sk)
while res: # 登录注册成功才进行上传下载
opt_lst2 = [('上传', upload), ('下载', download), ('退出', quit)]
func = choose_opt1(opt_lst2)
func(sk)
server
import os
import json # 格式的转换
import struct
import hashlib # 加密
import socketserver
import sys
class Auth:
@staticmethod # 静态方法,可以被类对象、子类对象等访问,只能访问属于类的属性,不能访问对象的属性
def get_md5(opt_dic): # defd定义函数
md5 = hashlib.md5(opt_dic['username'].encode('utf-8')) # md5不能被反解,加密是固定的一一对应的
md5.update(opt_dic['password'].encode('utf-8')) # 加密
pwd = md5.hexdigest() # 拿到字符串
return pwd
@classmethod # 类方法
def login(cls, opt_dic):
# 把密码按照之前的规则进行加密
pwd = cls.get_md5(opt_dic)
# 和文件中的用户名和密码进行比对
with open('userinfo', encoding='utf-8') as f: # encoding,连接要使用utf—8编码
for line in f:
user, password = line.strip().split('|')
if opt_dic['username'] == user and pwd == password:
dic = {'operate': 'login', 'flag': True}
return dic
else:
pass
dic = {'operate': 'login', 'flag': False}
return dic
@classmethod
def register(cls, opt_dic):
# 把密码按照自己的算法进行摘要
pwd = cls.get_md5(opt_dic)
# 把用户名和密码写在userinfo文件中
with open('userinfo', 'a', encoding='utf-8') as f:
a = f.write('%s|%s\n' % (opt_dic['username'], pwd))
print(a)
dic = {'operate': 'register', 'flag': True}
return dic
class Myserver(socketserver.BaseRequestHandler):
def mysend(self, dic):
str_d = json.dumps(dic)
self.request.send(str_d.encode('utf-8'))
def myrecv(self, protocol=False, msg_len=1024):
if protocol:
bytes_len = self.request.recv(4)
msg_len = struct.unpack('i', bytes_len)[0]
else:
pass
msg = self.request.recv(msg_len)
str_msg = msg.decode('utf-8')
opt_dic = json.loads(str_msg)
return opt_dic
def handle(self):
# conn==self.request
opt_dic = self.myrecv()
print(opt_dic)
if hasattr(Auth, opt_dic['operate']): # hasattr如果Auth有opt_dic的属性返回TURE,否则返回False
dic = getattr(Auth, opt_dic['operate'])(opt_dic) # getattr获取AUth的opt_dic属性
self.mysend(dic)
else:
pass
# 判断登陆的结果在dic中,如果登录注册成功,用户上传下载
if dic['flag']:
opt_dic = self.myrecv(True)
if opt_dic['operate'] == 'upload':
# 上传
remote_path = 'D:\FTP1\local'
filename = opt_dic['filename']
file_path = os.path.join(remote_path, filename) # 链接文件名
with open(file_path, 'wb') as f: # wb如果文件不存在则创建新文件,有则打开文件
while opt_dic['filesize'] > 0:
content = self.request.recv(1024)
f.write(content)
opt_dic['filesize'] -= len(content)
elif opt_dic['operate'] == 'download':
local_path = 'D:\FTP1\download'
filename = opt_dic['filename']
file_path = os.path.join(local_path, filename) # 链接文件名
with open(file_path, 'wb') as f:
while opt_dic['filesize'] > 0:
content = self.request.recv(1024)
f.write(content)
opt_dic['filesize'] -= len(content)
else:
os._exit(0)
else:
pass
sk = socketserver.ThreadingTCPServer(('127.0.0.1', 9006), Myserver) # sk对象,ip地址和端口号
sk.serve_forever()
注意上传或下载的储存文件位置不同可能会引起报错,server端先运行,然后运行client。
求点赞!!!