python 学习分享-实战篇高级的ftp
#server代码
import socketserver,os,hashlib Base_paht = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/db' class Server_ftp(socketserver.BaseRequestHandler):
def handle(self):
while 1:
try:
self.username = self.request.recv(1024).strip() #接受用户信息
if not self.username:continue
self.username_path = Base_paht + '/%s/' % self.username.decode() #获取用户文件地址
print(self.username.decode(), '连接成功!') #打印用户连接信息
self.request.send('连接服务器成功!'.encode())
while 1:
try:
self.data = self.request.recv(1024).strip() #接受客户端命令
print('-->',self.data)
if not self.data :continue
print('{} wrote:'.format(self.client_address[0]),self.username)#打印ip及用户名称
cmd_dic = self.data.decode() #命令编码
print('执行的命令为',cmd_dic)
if hasattr(self,cmd_dic + '_file'): #判断是否存在这条命令
self.request.send('{}命令可以被执行'.format(cmd_dic).encode())
func = getattr(self,cmd_dic + '_file') #反射
func()
else:
self.request.send('no'.encode()) #不存在发送错误信息
except ConnectionResetError as e:
# print('err',e)
break
except ConnectionResetError as e:
print(self.client_address[0],e)
break
def get_file(self):
filename = self.request.recv(1024).decode()
print('客户端想要获取的文件名称为:',filename)
if os.path.isfile(self.username_path + filename) :
file_size = os.stat(self.username_path + filename).st_size #确认文件大小
self.request.send(str(file_size).encode()) #发送文件大小
self.request.recv(1024) #接收please give me
f = open(self.username_path + filename,'rb')
self.request.send(f.read())
f.close()
confirm = self.request.recv(1024).decode()
print(confirm)
f_1 = open(self.username_path + filename, 'rb')
m2 = hashlib.md5()
m2.update(f_1.read())
f_1_m2 = m2.hexdigest()
f.close()
self.request.send(f_1_m2.encode())
print(self.request.recv(1024).decode()) else:
self.request.send('no'.encode()) #如果文件不存在,发送no信息
def put_file(self):
filename = self.request.recv(1024).decode()
if filename != 'no' :
self.request.send('服务器收到文件名称!'.encode())
file_size = self.request.recv(1024).decode()
self.request.send('服务器收到文件大小为{}'.format(file_size).encode())
f = open(self.username_path + filename,'wb') #直接写入,如果有就覆盖
confirm_size = 0
while confirm_size < int(file_size):
if int(file_size) - confirm_size > 1024: # 确保接受的准确性,拒绝粘包.
cal = 1024
else:
cal = int(file_size) - confirm_size
data = self.request.recv(cal)
confirm_size += len(data)
f.write(data)
f.close()
f_1 = open(self.username_path + filename,'rb')
m2 = hashlib.md5()
m2.update(f_1.read())
f_1_m2 = m2.hexdigest()
f_1.close()
self.request.send(f_1_m2.encode())
print(self.request.recv(1024).decode())
self.request.send('{}上传完成'.format(filename).encode()) # 返回服务器信息,表示下载完成 else:
print('客户端传送错误文件名称!') def open_file(self):
filename = self.request.recv(1024).decode()
self.request.send('服务器收到目录名称!'.encode())
self.request.recv(1024) #防止粘包
if os.path.exists(self.username_path + filename ):
self.request.send('yes'.encode())
self.request.recv(1024)
path_dir = os.listdir(self.username_path+ filename)
if path_dir == []: # 如果为空
self.request.send('nothing'.encode())
else:
self.request.send(str(path_dir).encode())
else:
self.request.send('no'.encode()) def look_file(self):
self.request.recv(1024) #接收返回的数据,防止粘包
path_dir = os.listdir(self.username_path)
if path_dir == []: #如果为空
self.request.send('nothing'.encode())
else:
self.request.send(str(path_dir).encode()) if __name__ =='__main__':
HOST,PORT = 'localhost' , 6969
server = socketserver.ThreadingTCPServer((HOST,PORT),Server_ftp)
print('----------->等待连接<------------')
server.serve_forever()
#client代码 import socket,os,pickle,hashlib,sys floder_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/user_floder'
user_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/conf'
server_db_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + '/server_ftp/db/' class Scoket_ftp(object):
# 客户端类
def __init__(self):
self.client = socket.socket() def client_user_register(self):
#用户注册
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
if not os.path.exists(user_path + '/%s'%username) :
pwd_md = hashlib.md5() #md5加密用户密码
pwd_md.update(bytes(password,encoding='utf-8'))
pwd_save = pwd_md.hexdigest()
pickle.dump({'username':username,'password':pwd_save},open(user_path + '/%s'%username,'wb'))
os.makedirs(server_db_path + username)
print('创建成功!')
else:
print('账户已经存在!') def client_user_login(self):
#身份验证
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
if os.path.exists(user_path + '/%s'%username) :
pwd_md = hashlib.md5() # md5加密用户密码
pwd_md.update(bytes(password,encoding='utf-8'))
pwd_save = pwd_md.hexdigest()
user_dic = pickle.load(open(user_path + '/%s'%username,'rb'))
if username == user_dic['username'] and pwd_save == user_dic['password'] :
print('%s登录成功'%username)
return username
else:
print('账户密码错误!')
return False
else:
print('账户密码错误!')
return False def client_conn(self,ip_addr,port):
#建立连接
while 1:
username = self.client_user_login()
if username :
self.client.connect((ip_addr, port))
self.client.send(username.encode())
print(self.client.recv(1024).decode())
break
else:
continue def help(self):
#帮助信息
print('''
-----------help-----------
look:查看当前目录下文件
open foldername:打开文件夹
get filename:下载文件
put filename:上传文件
''')
def client_interaction(self):
#交互
while 1:
self.help()
cmd = input('请输入操作命令:').strip()
if len(cmd.split()) == 1: #判断命令行长度,如果是1的话,在判断输入
if cmd == 'look': self.file_look()#使用look方法
elif cmd == 'exit':
self.file_exit()
else:
print('命令输入错误,请重新输入')
continue
elif len(cmd.split()) == 2: #长度为2,证明是带有前面的语句的
cmd_option, filename = cmd.split()
if hasattr(self,'file_' + cmd_option):
func = getattr(self,'file_' +cmd_option)
func(filename)
else:
continue
else:
continue
def file_look(self):
#查看
self.client.send('look'.encode()) #发送方法
print(self.client.recv(1024).decode()) # 服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
self.client.send('please give me!'.encode()) # 自动发送给服务器
print('文件目录:',self.client.recv(1024).decode()) #接收目录信息并打印
def file_get(self,filename):
#下载
self.client.send('get'.encode()) #先发送方法
print(self.client.recv(1024).decode()) #服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
self.client.send(filename.encode()) #再发送文件名称
confirm = self.client.recv(1024).decode() #服务器确认文件是否存在,如果存在返回文件大小,如果不存在,返回no
if confirm != 'no':
self.client.send('please give me!'.encode())
f = open(floder_path+'/'+filename,'wb') #在下载文件夹中创建该文件(如果存在,则替换)
confirm_cal = 0
rate = 1
while confirm_cal < int(confirm):
if int(confirm) - confirm_cal > 1024: #确保接受的准确性,拒绝粘包.
cal = 1024
else:
cal = int(confirm) - confirm_cal
data = self.client.recv(cal)
confirm_cal += len(data) #避免tcp拆包
f.write(data)
if int(confirm) > 102400:
if confirm_cal > int(confirm)/100*(rate+1) and rate<= 100 :
rate += 1
r = '\r[%s]%d%%' % ("=" * rate, rate)
sys.stdout.write(r)
sys.stdout.flush()
else:
continue
else:
r = '[%s]%d%%'%('='*100,100)
sys.stdout.write(r)
f.close()
self.client.send('{}下载完成'.format(filename).encode()) # 返回服务器信息,表示下载完成
f_1 = open(floder_path+'/'+filename,'rb') #判断一致性
m2 = hashlib.md5()
m2.update(f_1.read())
f_1_m2 = m2.hexdigest()
f_1.close()
f_1_m2_server = self.client.recv(1024).decode()
if f_1_m2 == f_1_m2_server :
print('\n下载完成!')
self.client.send('客户端已经成功获取完整文件!'.encode())
else:
print('传输异常')
self.client.send('客户端获取文件不完整或存在异常!'.encode())
else:
print('确认信息为no,文件可能不存在或有其他问题!') def file_put(self,filename):
#上传文件
self.client.send('put'.encode()) # 先发送方法
print(self.client.recv(1024).decode()) # 服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
if os.path.isfile(floder_path + '/' + filename):
self.client.send(filename.encode())
print(self.client.recv(1024).decode()) #拒绝粘包
cal = os.stat(floder_path + '/' + filename).st_size #获取文件大小
self.client.send(str(cal).encode()) #发送文件大小信息
print(self.client.recv(1024).decode()) #获取反馈
f = open(floder_path+'/'+filename,'rb') #打开文件
self.client.send(f.read())
f.close()
f_1 = open(floder_path + '/' + filename, 'rb') #一致性校验
m2 = hashlib.md5()
m2.update(f_1.read())
f_1_m2 = m2.hexdigest()
f_1.close()
f_1_m2_server = self.client.recv(1024).decode()
if f_1_m2 == f_1_m2_server:
print('上传完成!')
self.client.send('客户端已经成功上传完整文件!'.encode())
else:
print('传输异常')
self.client.send('客户端上传文件不完整或存在异常!'.encode())
print(self.client.recv(1024).decode())
else:
self.client.send('no'.encode())
print('查无此文件')
def file_open(self,filename):
self.client.send('open'.encode()) # 先发送方法
print(self.client.recv(1024).decode()) # 服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
self.client.send(filename.encode()) #发送目录名称
print(self.client.recv(1024).decode())
self.client.send('防止粘包'.encode())
confirm = self.client.recv(1024).decode() # 服务器确认文件是否存在,如果存在返回yes,如果不存在,返回no
if confirm != 'no':
self.client.send('please give me!'.encode()) #自动发送给服务器
file_dir = self.client.recv(1024).decode()
print(file_dir) else:
print('确认信息为no,目录可能不存在或有其他问题!') if __name__ == '__main__' :
socket_ftp = Scoket_ftp()
option = input('''
---------option----------
1.创建用户
2.登录
3.退出
''').strip()
if option == '':
socket_ftp.client_user_register()
elif option == '':
socket_ftp.client_conn('localhost',6969) socket_ftp.client_interaction()
elif option == '':
exit() else:
print('wrong!')
exit()
python 学习分享-实战篇高级的ftp的更多相关文章
- python 学习分享-实战篇简单的ftp
import socket import os import time import pickle Basedb = os.path.dirname(os.path.dirname(os.path.a ...
- python 学习分享-实战篇选课系统
# 角色:学校.学员.课程.讲师 # 要求: # 1. 创建北京.上海 2 所学校 # 2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海开 # ...
- python 学习分享-实战篇类 Fabric 主机管理程序开发
# 类 Fabric 主机管理程序开发: # 1. 运行程序列出主机组或者主机列表 # 2. 选择指定主机或主机组 # 3. 选择让主机或者主机组执行命令或者向其传输文件(上传/下载) # 4. 充分 ...
- python 学习分享-实战篇增删改查作业
一大波函数来袭 作业要求: 1本次作业通过空格及逗号,将文件拆分成列表,在通过判断add.del.update.select等关键字,来判断用户执行的是哪种命令,根据不同的命令调用不同的函数去处理. ...
- python 学习分享-函数篇
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可以自己创建函数,这 ...
- python 学习分享-字典篇
python字典(Dictionary) dict是无序的 key必须是唯一切不可变的 a={'key1':'value1','key2':'value2'} 字典的增删改查 a['key3']='v ...
- python 学习分享-基础篇
1.python起手式 写下第一个代码,打印‘hello world’ print('hello world') 2.变量 变量是为了存储信息,在程序中被调用,标识数据名称或类型. 变量定义的规则: ...
- python 学习分享-函数篇2
递归 自己玩自己的函数: 1. 必须有一个明确的结束条件 2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少 3. 递归效率不高,递归层次过多会导致栈溢出 递归例子和二分查找都放在里面了 ...
- Python学习笔记基础篇——总览
Python初识与简介[开篇] Python学习笔记——基础篇[第一周]——变量与赋值.用户交互.条件判断.循环控制.数据类型.文本操作 Python学习笔记——基础篇[第二周]——解释器.字符串.列 ...
随机推荐
- POJ-2377 Bad Cowtractors---最大生成树
题目链接: https://vjudge.net/problem/POJ-2377 题目大意: 给一个图,求最大生成树权值,如果不连通输出-1 思路: kruskal算法变形,sort按边从大到小排序 ...
- http知识补充
在我的职业生涯中,没怎么重视过这http四个字,想当然的觉得不就是个网页请求嘛就没怎么当回事,而且很多http相关的长篇大论一听就困,真心是弄不下去,但是就是这种观念导致我后期的工作中不断的挖坑,不断 ...
- C++STL之vector向量容器
vector向量容器 vector向量容器不但能向数组一样对元素进行随机访问, 还能在尾部插入元素 vector具有内存自动管理的功能, 对于元素的插入和删除, 可动态调整所占的内存空间 vect ...
- Java 文件切割工具类
Story: 发送MongoDB 管理软件到公司邮箱,工作使用. 1.由于公司邮箱限制附件大小,大文件无法发送,故做此程序用于切割大文件成多个小文件,然后逐个发送. 2.收到小文件之后,再重新组合成原 ...
- vue input框设置值 一般对象都是通过打点形式取值
- Matlab将矩阵保存为图像
imwrite(image,'image.jpg'); image为矩阵的内容 image.jpg为要保存的图像的名字
- Intel MKL 多线程设置
对于多核程序,多线程对于程序的性能至关重要. 下面,我们将对Intel MKL 有关多线程方面的设置做一些介绍: 我们提到MKL 支持多线程,它包括的两个概念:1>MKL 是线程安全的: MKL ...
- glocktop
glocktop: Display or print active GFS2 locks. Index of glocktop man page Read glocktop man page on L ...
- 前端jQuery之动画操作及相关演示
1.显示动画 1.1无参数,直接让指定的元素显示出来 $("div").show(); 1.2通过控制宽高,透明度,display属性逐渐显示,指定时间现实完毕 $('div'). ...
- JS - 给数组的原型添加去掉重复元素的distinct方法
/* 调用完该方法,原数组只留下非重复的数据 返回一个数组,里面是依次出现的重复元素 */Array.prototype.distinct = function () { var removeA ...