本次Ftp的案例使用面向对象的编程方式。
其中使用反射的机制来调用本身的put和get以及cmd方法。
借用socketserver模块来实现多用户登录。具体看代码
#!/usr/bin/env python
# --coding = utf-8
# Author Allen Lee
import socket,subprocess,socketserver,json
#创建FtpServer,并继承socketserver 父类,来实现多用户登录
class FtpServer(socketserver.BaseRequestHandler):
def handel(self):
# while True:
# conn,addr = server.accept()
# print(addr)
server_tag = False
res = self.request.recv(1024)
if len(res) == 0:
return error
#使用json格式化接收client传来的用户信息
userinfo = json.loads(str(res,encoding='utf-8'))
#此处用了伪代码,意为进行用户验证
if userinfo[0].get('username') == 'username' and userinfo[0].get('password') == 'password':
server_tag = True
return ok
else:
return error
#通过判断标签值来进行权限检验
while server_tag:
res = self.request.recv(1024)
reg = str(res,encoding='utf-8')
#此处使用反射原理,来依次调用本身的上传、下载、命令行方法
if reg.startswith('put'):
if hasattr(self,put):
func = getattr(self,server_put)
func(reg)
if reg.startswith('get'):
if hasattr(self,get):
func = getattr(self,server_get)
func(reg)
if reg.startswith('cmd'):
if hasattr(self,cmd):
func = getattr(self,server_cmd)
func(reg)
#以下为具体方法内容
def server_put(self):
pass
def server_get(self):
pass
def server_cmd(self):
while True:
try:
res_data = self.request.recv(1024)
res_signal = str(res_data,encoding='utf-8')
if len(res_data) == 0 :break
#通过匹配‘put’关键字来确定执行put相关代码
elif res_signal.startswith('put'):
pass
#通过匹配‘get’关键来执行上传相关代码
elif res_signal.startswith('get'):
pass
#否则将当作正常命令来执行
else:
ret = subprocess.Popen(res_signal,shell=True,stdout=subprocess.PIPE)
res_msg = ret.stdout.read()
if len(res_msg) == 0:
send_data = 'cmd_err'
else:
send_data = str(res_msg,encoding='gbk')
print(send_data, type(send_data))
#通知客户端,本次包的总大小,并打上‘ready’的signal,让client来抓取,注意这里用“|”为分隔符
send_tag = 'ready|%d' %(len(res_msg))
self.request.send(bytes(send_tag,encoding='utf-8'))
#为了调试代码进度所添加的输出
print(send_tag)
#cilent在收到‘ready’的标签后,给服务端回一个‘start’,通知服务端可以发包
recv_data = self.request.recv(1024)
recv_tag = str(recv_data,encoding='utf-8')
#在服务端接收到来时client的确认信息之后,则开始发送client请求的信息;
if recv_tag == 'start':
self.request.send(bytes(send_data,encoding='utf-8'))
else:
self.request.send(bytes('do not receive the start signal',encoding='utf-8'))
except Exception:
break
conn.close()
if __name__ == '__main__':
#调用socketserver的ThreadingTCPServer,来实现多线程
server = socketserver.ThreadingTCPServer(('127.0.0.1',8088),FtpServer.run())
server.serve_forever()
Client端:
#!/usr/bin/env python
# --coding = utf-8
# Author Allen Lee
import socket
from lib import commons
#创建FtpClient类
class FtpClient:
#在构造函数中初始化client连接server的功能
def __init__(self,ip,port):
self.ip = ip
self.port = port
self.client = socket.socket()
self.client.connect((self.ip,self.port))
self.tag = False
#验证用户名密码,输错有三次机会,根据server端返回的信息来判断是否验证成功
for i in range(3):
username = input('please input your username:')
passwd = input('please input your passwd:')
password = commons.md5(passwd)
userinfo = {"username":username,"password":password }
self.client.send(bytes(json.dumps(userinfo),encoding='utf-8'))
ret = self.client.recv(1024)
res_check = str(ret,encoding='utf-8')
if res_check == 'ok':
self.tag = True
break
else:
continue
print("your username or passwd is wrong")
self.client.close()
#循环使用进程
while True:
send_signal = input('>> :').strip()
if len(send_signal) == 0:continue
#权限验证
while self.tag:
if hasattr(self,send_signal):
func = getattr(self,send_signal)
else:
func = getattr(self,'cmd')
func(args)
def put(self,reg):
# file_path =
pass
def get(self,reg):
pass
def cmd(self,reg):
while True:
res_firt = self.client.recv(1024)
send_data = reg
send_msg = bytes(send_data,encoding='utf-8')
self.client.send(send_msg)
res_data = self.client.recv(1024)
res_tag = str(res_data,encoding='utf-8')
#client接收并解析服务端发回的信息是否是ready开头的,以此判断是否要开始发包了
if res_tag.startswith('ready'):
#将ready后的数字传给res_total,用于之后的信息回显,同理也可以来做一个进度条的显示功能
res_total = int(res_tag.split('|')[1])
#初始化当前接收的信息节点数值
res_now = 0
# cilent在收到‘ready’的标签后,给服务端回一个‘start’,通知服务端可以发包
client.send(bytes('start',encoding='utf-8'))
#在当前信息值不大于总值的情况下,循环获取并打印服务端发过来的信息
while res_now < res_total:
#设置recv最小接收信息单元 的字节数
res_data = self.client.recv(1024)
res_now += len(res_data)
print('total:%s----now:%s'%(res_total,res_now))
print(str(res_data,encoding='utf-8'))
def exit(self):
self.tag = False
client.close()
if __name__ == '__main__':
client = FtpClient('127.0.0.1',8088)
client()