Python笔记_33_FTP上传下载文件

FTP上传下载文件

实现:服务器与客户端的登陆,注册,上传文件,下载文件,退出
在这里插入图片描述
server.py

import socketserver
import json
import hashlib
import os
import struct

# 获取当前路径,方便项目移植时,路径正确
base_path = os.path.dirname(__file__)
# 获取当前账户文件路径
userinfo = os.path.join(base_path,"db","userinfo.txt")
class Auth:
	@staticmethod
	def md5(usr,pwd):
		md5_obj = hashlib.md5(usr.encode())
		md5_obj.update(pwd.encode())
		return md5_obj.hexdigest()
		
	@classmethod
	def register(cls,opt_dic):
		# 1.先检测账户文件是否已经有该账户
		with open(userinfo,mode="r",encoding="utf-8") as fp:
			for line in fp:
				username = line.split(":")[0]
				if username == opt_dic['user']:
					return {'result':False,"info":"用户名存在了"}

		# 2.当前用户可以注册
		with open(userinfo,mode="a",encoding="utf-8") as fp:
			fp.write("%s:%s\n" % (opt_dic['user'],cls.md5(opt_dic['user'],opt_dic['passwd'])))				
		
		# 将来用户上传文件时候,为当前用户创建上传文件夹
		# 未完待续...
		return {'result':True,"info":"注册成功"}
		
	@classmethod
	def login(cls,opt_dic):
		with open(userinfo,mode="r",encoding="utf-8") as fp:
			"""
			for... else python特有
			当循环遇到break,或者return 意外终止时,不执行else分支,其他情况都执行else
			
			"""
			for line in fp:
				username,password = line.strip().split(":")
				if username == opt_dic['user'] and password == cls.md5(opt_dic['user'],opt_dic['passwd']):
					return {"result":True,"info":"登陆成功"}
			else:
				return {"result":False,"info":"登录失败"}
	@classmethod
	def myexit(cls,opt_dic):
		return {'result':"myexit"}
	
class FTPServer(socketserver.BaseRequestHandler):
	def handle(self):
		while True:
			opt_dic = self.myrecv()
			# 通过反射调用Auth这个类中相应方法-*
			if hasattr(Auth,opt_dic['operate']):
				res = getattr(Auth,opt_dic['operate'])(opt_dic)
				# print(res)
				if res['result'] == "myexit":
					return 
		
				# 发送给客户端用户处理结果
				self.mysend(res)
				
				# 等待用户操作第二轮界面内容
				if res['result']:
					opt_dic = self.myrecv()
					
					if opt_dic['operate'] == "myexit":
						return 
						
					# 走到这个位置越过了退出的情况,只剩下上传和下载了
					if hasattr(self,opt_dic['operate']):
						getattr(self,opt_dic["operate"])(opt_dic)
						
					#{'operate': 'download', 'filename': 'ceshimovie.mp4'}
					print(opt_dic)
			
			else:
				dic = {"result":False,"info":"没有该操作"}
				self.mysend(dic)
	def myrecv(self):
		info = self.request.recv(1024)
		opt_str = info.decode()
		opt_dic = json.loads(opt_str)
		return opt_dic
		
	def mysend(self,send_info,sign=False):
		send_info = json.dumps(send_info).encode()
		if sign:
			send_len = struct.pack("i",len(send_info))
			#1发数据长度
			self.request.send(send_len)
		#2发具体数据
		self.request.send(send_info)
	
	def download(self,opt_dic):
		# 先判断是否存在该文件
		filename = opt_dic['filename']
		file_abs = os.path.join(base_path,"video",filename)
		if os.path.exists(file_abs):
			# 1.先告诉用户,操作行为合法,存在该文件
			dic = {"result":True,"info":"该文件存在"}
			self.mysend(dic,True)
			# 2.把文件大小和文件名传回去
			filesize = os.path.getsize(file_abs)
			dic = {"filename":filename,"filesize":filesize}
			self.mysend(dic,True)
			
			
			# 3.开始传文件内容
			with open(file_abs,mode="rb") as fp:
				while filesize:
					# 最多读2048字节
					content = fp.read(2048)
					self.request.send(content)
					filesize -= len(content)
			print("服务端下载完毕")
		else:
			dic = {'result':False,"info":"文件不存在"}
			self.mysend(dic)
		
myserver = socketserver.ThreadingTCPServer( ("127.0.0.1",9000) , FTPServer)
myserver.serve_forever()


client.py

import socket
import json
import struct
import os

sk = socket.socket()
sk.connect( ("127.0.0.1",9000) )

# 收发数据逻辑
# ...

# 收数据
def myrecv(info_len=1024,sign = False):
	if sign:
		info_len = sk.recv(4)
		# 返回元组
		info_len = struct.unpack("i",info_len)[0]
	file_info = sk.recv(info_len).decode()
	file_dic = json.loads(file_info)
	return file_dic

# 登录注册
def auth(opt):
	'''
	opt login or register
	'''
	usr = input("username: ").strip()
	pwd = input("password: ").strip()
	
	# 用户名,密码,操作行为
	dic = {'user':usr,"passwd":pwd,"operate":opt}
	str_dic = json.dumps(dic)
	sk.send(str_dic.encode())
	
	# 接受服务器返回的响应消息
	return myrecv(info_len=1024)

# 注册
# res = auth("register")
# print(res)
def register():
	res = auth("register")
	return res
	
# 登录
# res = auth("beatdoudou")
# res = auth("login")
# print(res)
def login():
	res = auth("login")
	return res

# 退出
def myexit():
	opt_dic = {"operate":"myexit"}
	sk.send(json.dumps(opt_dic).encode())
	exit("欢迎下次再来")
# myexit()

def download():
	operate_dict = {
		'operate':"download",
		"filename":'ceshimovie.mp4'	
	}
	opt_str = json.dumps(operate_dict)
	sk.send(opt_str.encode("utf-8"))
	# 接受服务给客户端是否文件存在的这样的判断
	res = myrecv(sign=True)
	# print(res)
	if res['result']:
		# 接受文件大小和文件名
		dic = myrecv(sign=True)
		# 创建文件夹
		try:
			os.mkdir("mydownload")
		except:
			pass
		# 接受文件
		# {'filename': 'ceshimovie.mp4', 'filesize': 20724134}
		with open("./mydownload/"+dic['filename'],mode="wb") as fp:
			while dic['filesize']:
				content = sk.recv(2048)
				fp.write(content)
				dic['filesize'] -= len(content)
	
		print("客户端下载完毕")
	else:
		print("没有该文件")



operate_lst1 = [("登录",login),("注册",register),("退出",myexit)]
operate_lst2 = [("下载",download),("退出",myexit)]


# 主函数进行统一调用 
'''
(1, ('登录', <function login at 0x0000018DFB759E18>))
(2, ('注册', <function register at 0x0000018DFB759D90>))
(3, ('退出', <function myexit at 0x0000018DFB759EA0>))
'''
def main(operate_lst):
	for i,tup in enumerate(operate_lst,start=1):
		print(i,tup[0])
	num = int(input("选择执行的序号>>>").strip())
	# 直接调用对应的函数
	res = operate_lst[num-1][1]() # login() register() myexit()
	# 返回结果
	return res
# res = main(operate_lst1)
# print(res)


# 循环调用
while True:
	# 开启第一套操作界面
	res = main(operate_lst1)
	if res['result']:
		res = main(operate_lst2)
		print(res)


sk.close()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值