Python小程序之-模拟FTP服务器(待补充)

模拟FTP服务器 socketserver
(1)登录 (2)注册 (3) 上传[待补充] (4) 下载
在这里插入图片描述

server.py

# 服务端
import socketserver
import json
import hashlib
import os
import struct


# 找当前数据库文件所在的绝对路径
base_path = os.path.dirname(__file__)
# /mnt/hgfs/python31_gx/day36/db/userinfo.txt
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:
			strvar = "%s:%s\n" % (   opt_dic["user"] , cls.md5(   opt_dic["user"],opt_dic["passwd"]   )    )
			fp.write(strvar)
					
		"""
			当用户上传的时候,给他创建一个专属文件夹,存放数据
		"""
		
		# 3.返回状态
		return {
    
    "result":True,"info":"注册成功"}
		
	@classmethod
	def login(cls,opt_dic):
		with open(userinfo , mode="r" , encoding="utf-8") as fp:
			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":"登录成功"}
			 
			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()
			print(opt_dic) # {'user': 'wangwen', 'passwd': '111', 'operate': 'register'}
			if hasattr(Auth,opt_dic["operate"]):
				# print(  getattr(Auth,"register")   )
				res = getattr(Auth,opt_dic["operate"])(opt_dic) # login(opt_dic)
				
				# 如果接受的操作是myexit,代表退出
				if res["result"] == "myexit":
					return 
				
				# 把状态发送给客户端
				self.mysend(res)
				
				# 开启第二套操作界面的逻辑
				if res["result"] :
					while True:
						# 接受用户发过来的第二套界面的数据
						opt_dic = self.myrecv()
						print(opt_dic) # {'operate': 'download', 'filename': 'ceshi123.mp4'}
						
						if opt_dic["operate"] == "myexit":
							return 
							
							
						# 通过FTPServer反射出下载的方法
						""""""
						if hasattr(self,opt_dic["operate"]):
							getattr(self,opt_dic["operate"])(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:
			res = struct.pack("i",len(send_info))
			# 1.发送数据的长度
			self.request.send(res)
		
		# 2.发送真实的数据
		self.request.send(send_info)
		
		
	def download(self,opt_dic):
		filename = opt_dic["filename"]
		# (1) 判断文件是否存在
		# 拼接绝对路径
		file_abs = os.path.join(base_path,"video",filename)
		if os.path.exists(file_abs):
			# 1号.告诉用户,文件存在,可以下载
			dic = {
    
    "result":True,"info":"文件存在,可以下载"}
			self.mysend(dic,sign=True)
			
			# 2号.发送 文件名字 和 文件大小
			filesize = os.path.getsize(file_abs)
			dic = {
    
    "filename":filename , "filesize":filesize}
			self.mysend(dic,sign=True)
			
			# 3号.真正开始发送数据
			with open(file_abs,mode="rb") as fp:
				while filesize:
					content = fp.read(1024000)
					self.request.send(content)
					filesize -= len(content)
			print("服务器下载完毕")

		else:
			dic = {
    
    "result":False,"info":"文件不存在"}
			self.mysend(dic,sign=True)
		
		
		

# 设置一个端口可以绑定多个程序
# socketserver.TCPServer.allow_reuse_address = True
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:
		# 1. 接受发送数据的实际长度
		info_len = sk.recv(4)
		info_len = struct.unpack("i",info_len)[0]
		
	# 2.接受服务端响应的真实的数据
	file_info = sk.recv(info_len).decode()
	file_dic = json.loads(file_info)
	return file_dic


# 处理收发数据的逻辑
def auth(opt):
	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("utf-8"))
	return myrecv()
	


# 注册
def register():
	res = auth("register")
	return res

# 登录
def login():
	res = auth("login")
	return res
	
# 退出
def myexit():	
	opt_dic = {
    
    "operate":"myexit"}
	sk.send(json.dumps(opt_dic).encode())
	exit("欢迎下次再来")
	
def download():
	operate_dict = {
    
    
		"operate" : "download",
		"filename":"ceshi123.mp4"	
	}
	# 把要下载的数据给服务端
	opt_str = json.dumps(operate_dict)
	sk.send(opt_str.encode("utf-8"))
	# 接受服务端发送过来的数据 (是否可以操作)[对应服务端的1号发送]
	res = myrecv(sign=True)
	# {'result': True, 'info': '文件存在,可以下载'}
	print(res)
	
	#
	# (1) 如果文件存在,在本地创建一个文件夹
	if res["result"]:	
		try:
			os.mkdir("mydownload")
		except:
			pass
	
		# (2) 接受 文件名字 和 文件大小 对应服务端的2号发送
		dic = myrecv(sign=True)
		print(dic)
	
		# (3) 接受真实的文件 对应服务端的3号发送
		with open("./mydownload/" + dic["filename"],mode="wb") as fp:
			while dic["filesize"]:
				content = sk.recv(1024000)
				fp.write(content)
				dic["filesize"] -= len(content)
		
		print("客户端下载完毕")
		
	else:
		print("没有该文件")
	
# 第一套操作界面
#                      0                  1                2
operate_lst1 = [ ("登录",login) ,("注册",register) , ("退出",myexit) ]
# 第二套操作界面
operate_lst2 = [ ("下载",download) , ("退出",myexit)]



"""
1.登录
2.注册
3.退出

1 ('登录', <function login at 0x7ff7cf171a60>)
2 ('注册', <function register at 0x7ff7cf17e620>)
3 ('退出', <function myexit at 0x7ff7cf171ae8>)
"""



def main(operate_lst):
	for i,tup in enumerate(operate_lst,start=1):
		print(i , tup[0])
	num = int(input("请选择执行的操作>>> ").strip()) # 1 2 3
	# 调用函数
	# print(operate_lst1[num-1]) ('退出', <function myexit at 0x7f801e34aa60>)
	# print(operate_lst1[num-1][1]) <function myexit at 0x7f801e34aa60>
	# operate_lst1[num-1][1]() myexit()
	res = operate_lst[num-1][1]()
	return res
	
while True:
	# 开启第一套操作界面
	res = main(operate_lst1)
	""""""
	if res["result"]:
		# 开启第二套操作界面
		while True:			
			res = main(operate_lst2)

	
sk.close()

猜你喜欢

转载自blog.csdn.net/qq_45957580/article/details/108294271