#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的更多相关文章

  1. python 学习分享-实战篇简单的ftp

    import socket import os import time import pickle Basedb = os.path.dirname(os.path.dirname(os.path.a ...

  2. python 学习分享-实战篇选课系统

    # 角色:学校.学员.课程.讲师 # 要求: # 1. 创建北京.上海 2 所学校 # 2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海开 # ...

  3. python 学习分享-实战篇类 Fabric 主机管理程序开发

    # 类 Fabric 主机管理程序开发: # 1. 运行程序列出主机组或者主机列表 # 2. 选择指定主机或主机组 # 3. 选择让主机或者主机组执行命令或者向其传输文件(上传/下载) # 4. 充分 ...

  4. python 学习分享-实战篇增删改查作业

    一大波函数来袭 作业要求: 1本次作业通过空格及逗号,将文件拆分成列表,在通过判断add.del.update.select等关键字,来判断用户执行的是哪种命令,根据不同的命令调用不同的函数去处理. ...

  5. python 学习分享-函数篇

    函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可以自己创建函数,这 ...

  6. python 学习分享-字典篇

    python字典(Dictionary) dict是无序的 key必须是唯一切不可变的 a={'key1':'value1','key2':'value2'} 字典的增删改查 a['key3']='v ...

  7. python 学习分享-基础篇

    1.python起手式 写下第一个代码,打印‘hello world’ print('hello world') 2.变量 变量是为了存储信息,在程序中被调用,标识数据名称或类型. 变量定义的规则: ...

  8. python 学习分享-函数篇2

    递归 自己玩自己的函数: 1. 必须有一个明确的结束条件 2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少 3. 递归效率不高,递归层次过多会导致栈溢出 递归例子和二分查找都放在里面了 ...

  9. Python学习笔记基础篇——总览

    Python初识与简介[开篇] Python学习笔记——基础篇[第一周]——变量与赋值.用户交互.条件判断.循环控制.数据类型.文本操作 Python学习笔记——基础篇[第二周]——解释器.字符串.列 ...

随机推荐

  1. POJ-3349 Snowflake Snow Snowflakes---最小表示法

    题目链接: https://vjudge.net/problem/POJ-3349 题目大意: 每个雪花都有六个分支,用六个整数代表,这六个整数是从任意一个分支开始,朝顺时针或逆时针方向遍历得到的.输 ...

  2. POJ-3669 Meteor Shower---BFS+预处理

    题目链接: https://vjudge.net/problem/POJ-3669 题目大意: 巨大流星雨即将袭来.每个流星会对击中的地方以及周围(上下左右四格)造成破坏.Bessie开始时位于(0, ...

  3. 【转】NodeJS教程--基于ExpressJS框架的文件上传

    本文是翻译的一篇文章,原文地址:Handle File Uploads in Express (Node.js). 在NodeJS发展早期上传文件是一个较难操作的功能,随后出现了formidable. ...

  4. 用命令关键字(Cmdlet Keyworlds)编写面向管道的脚本

    使用begin  process和end关键字 把你的脚本分成 初始化 处理和清楚几个区域

  5. 解决windows下Composer因php_openssl扩展缺失而安装失败的问题

    Composer( https://getcomposer.org/ )是PHP下的一个依赖管理工具.你可以在你的项目中声明你所需要用到的类库,然后Composer会在项目中为你安装它们.如果你了解N ...

  6. BIO与NIO

    BIO与NIO 1.传统BIO (1)特点 面向数据流 阻塞式传输 一个客户端对应一个线程 在客户机增多的情况下,线程资源随之增多,会造成cpu资源枯竭 (2)需求 ​ 客户机向服务器输出字符串,逐一 ...

  7. Problem 1004-2017 ACM/ICPC Asia Regional Shenyang Online

    题目来源:array array array Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...

  8. jquery横向手风琴效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 深入理解PHP数组函数和预定义接口

    一. PHP对数组的过滤 函数: array_filter(p1[,p2]) 参数p1是要过滤的数组,参数p2是自定义过滤会掉函数(可以是匿名函数) 例子: <?php $arr = ['',n ...

  10. #Python编程从入门到实践#第四章笔记

    #Python编程从入门到实践#第四章笔记   操作列表 ​​​1.遍历列表 使用for循环,遍历values列表 for value in values: print(value) 2.数字列表 使 ...