一、要求

1、用户md5认证

2、支持多用户同时登陆(并发)

3、进入用户的命令行模式,支持cd切换目录,ls查看目录子文件

4、执行命令(ipconfig)

5、传输文件:

    a、支持断点续传

    b、传输中显示进度条

二、思路

1.客户端用户登录和注册:

a、客户端仅提供用户名和密码,选择登录或注册,
b、服务器端进行注册并将加密后的密码写入文件,最后返回给客户端是否登录或注册成功

2.ls和cd命令

a、客户端输入命令,服务器端处理并返回给客户端

3.执行命令:

a、客户端发送需要执行的命令
b、服务器端执行命令,并返回客户端需要接收该命令的次数s=r[0]+1,其中r=divmod(结果总长度,1024)
c、客户端收到次数,告诉服务端已经收到
d、服务端发送执行结果,客户端进行for循环接收该结果

4.发送文件:

a、客户端输入文件路径(测试版路径为:f.png),发送文件名和文件大小
b、服务器端检测指定目录是否含有该文件,如果没有,返回给客户端字符串s,即从头开始发送start,has_recv=0
如果有,即需要断点续传,返回给客户端已经上传了多少has_recv
c、客户端接收返回值,并seek到has_recv的位置,进行循环收发,打印当前进度,直到传输完毕。

注:本程序可循环接收用户选择传输文件和执行命令

三、代码

配置文件:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__)) #配置文件的上层目录
NEW_FILENAME=os.path.join(BASE_DIR,'view') #新文件目录
NAME_PWD=os.path.join(BASE_DIR,'db','name_pwd') #用户名和密码目录
USER_FILE=os.path.join(BASE_DIR,'db')

服务器端:

#!/usr/bin/env python
# -*- coding: utf-8 -*- import sys,os
import time
import socket
import hashlib
import pickle
import subprocess
import socketserver
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from config import settings new=settings.NEW_FILENAME
class Myserver(socketserver.BaseRequestHandler): def recv_file(self):
'''
文件传输
:return:
'''
conn=self.request
a=str(conn.recv(1024),encoding='utf-8')
file_size,file_name=a.split(',')
new_file_name=os.path.join(new,file_name)
if file_name in new: #检测文件是否已存在,涉及断点续传
has_recv=os.stat(new).st_size #计算临时文件大小
conn.sendall(bytes(has_recv,encoding='utf-8'))
with open(new_file_name,'ab') as f: #追加模式
while has_recv<=int(file_size):
data=conn.recv(1024)
f.write(data)
has_recv+=len(data)
else:
has_recv=0
conn.sendall(bytes('s',encoding='utf-8')) # 客户端收到字符串s,从0开始发送
with open(new_file_name,'wb') as f:
while has_recv<=int(file_size):
data=conn.recv(1024)
f.write(data)
has_recv+=len(data) def command(self):
'''
执行命令
:return:
'''
conn=self.request
a=conn.recv(1024)
ret=str(a,encoding='utf-8')
ret2 = subprocess.check_output(ret, shell=True)
r=divmod(len(ret2),1024)
s=r[0]+1 #客户端需要接收的次数
conn.sendall(bytes(str(s),encoding='utf-8'))
conn.recv(1024) #确认客户端收到需要接收的次数 conn.sendall(ret2) def md5(self,pwd):
'''
对密码进行加密
:param pwd: 密码
:return:
'''
hash=hashlib.md5(bytes('xx7',encoding='utf-8'))
hash.update(bytes(pwd,encoding='utf-8'))
return hash.hexdigest() def login(self,usrname,pwd):
'''
登陆
:param usrname: 用户名
:param pwd: 密码
:return:是否登陆成功
'''
conn=self.request
s=pickle.load(open(settings.NAME_PWD,'rb'))
if usrname in s:
if s[usrname]==self.md5(pwd): #和加密后的密码进行比较
return True
else:
return False
else:
return False def regist(self,usrname,pwd):
'''
注册
:param usrname: 用户名
:param pwd: 密码
:return:是否注册成功
''' conn=self.request
s=pickle.load(open(settings.NAME_PWD,'rb'))
if usrname in s:
return False
else:
s[usrname]=self.md5(pwd)
mulu=os.path.join(settings.USER_FILE,usrname)
os.makedirs(mulu,'a')
pickle.dump(s,open(settings.NAME_PWD,'wb'))
return True def before(self,usrname,pwd,ret):
'''
判断注册和登陆,并展示用户的详细目录信息,支持cd和ls命令
:return:
'''
conn=self.request
if ret=='':
r=self.login(usrname,pwd)
if r:
conn.sendall(bytes('y',encoding='utf-8'))
else:
conn.sendall(bytes('n',encoding='utf-8'))
elif ret=='':
# print(usrname,pwd)
r=self.regist(usrname,pwd)
if r:
conn.sendall(bytes('y',encoding='utf-8'))
else:
conn.sendall(bytes('n',encoding='utf-8'))
def usr_file(self,usrname):
'''
展示用户的详细目录信息,支持cd和ls命令
:param usrname: 用户名
:return:
'''
conn=self.request
conn.recv(1024)
mulu=os.path.join(settings.USER_FILE,usrname)
conn.sendall(bytes(mulu,encoding='utf-8'))
while True:
b=conn.recv(1024)
ret=str(b,encoding='utf-8')
try:
a,b=ret.split(' ',1)
except Exception as e:
a=ret
if a=='cd':
if b=='..':
mulu=os.path.dirname(mulu)
else:
mulu=os.path.join(mulu,b)
conn.sendall(bytes(mulu,encoding='utf-8'))
elif a=='ls':
ls=os.listdir(mulu)
print(ls)
a=','.join(ls)
conn.sendall(bytes(a,encoding='utf-8'))
elif a=='q':
break def handle(self):
conn=self.request
conn.sendall(bytes('welcome',encoding='utf-8'))
b=conn.recv(1024)
ret=str(b,encoding='utf-8')
print(ret)
conn.sendall(bytes('b ok',encoding='utf-8'))
c=conn.recv(1024)
r=str(c,encoding='utf-8')
usrname,pwd=r.split(',')
self.before(usrname,pwd,ret) #登陆或注册验证
self.usr_file(usrname) #展示用户的详细目录信息,支持cd和ls命令
while True:
a=conn.recv(1024)
conn.sendall(bytes('收到a',encoding='utf-8'))
ret=str(a,encoding='utf-8')
if ret=='':
self.recv_file()
# conn.sendall(bytes('file ok',encoding='utf-8'))
elif ret=='':
self.command()
elif ret=='q':
break
else:
pass if __name__=='__main__':
sever=socketserver.ThreadingTCPServer(('127.0.0.1',9999),Myserver)
sever.serve_forever()

客户端:

#!/usr/bin/env python
# -*- coding: utf-8 -*- import sys
import time
import os
import socket
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from config import settings def send_file(file_path):
'''
发送文件
:param file_name:文件名
:return:
'''
size=os.stat(file_path).st_size
file_name=os.path.basename(file_path)
obj.sendall(bytes(str(size)+','+file_name,encoding='utf-8')) #发送文件大小和文件名
ret=obj.recv(1024) #接收已经传了多少
r=str(ret,encoding='utf-8')
if r=='s': #文件不存在,从头开始传
has_send=0
else: #文件存在
has_send=int(r) with open(file_path,'rb') as f:
f.seek(has_send) #定位到已经传到的位置
while has_send<size:
data=f.read(1024)
obj.sendall(data)
has_send+=len(data)
sys.stdout.write('\r') #清空文件内容
time.sleep(0.2)
sys.stdout.write('已发送%s%%|%s' %(int(has_send/size*100),(round(has_send/size*40)*'★')))
sys.stdout.flush() #强制刷出内存
print("上传成功\n") def command(command_name):
'''
执行命令
:param command_name:
:return:
'''
obj.sendall(bytes(command_name,encoding='utf-8'))
ret=obj.recv(1024) #接收命令需要接收的次数
obj.sendall(bytes('收到次数',encoding='utf-8'))
r=str(ret,encoding='utf-8')
for i in range(int(r)): #共需要接收int(r)次
ret=obj.recv(1024) #等待客户端发送
r=str(ret,encoding='GBK')
print(r) def login(usrname,pwd):
'''
登陆
:param usrname:用户名
:param pwd:密码
:return:是否登陆成功
'''
obj.sendall(bytes(usrname+','+pwd,encoding='utf-8'))
ret=obj.recv(1024)
r=str(ret,encoding='utf-8')
if r=='y':
return 1
else:
return 0 def regist(usrname,pwd):
'''
注册
:param usrname:用户名
:param pwd:密码
:return:是否注册成功
'''
obj.sendall(bytes(usrname+','+pwd,encoding='utf-8'))
ret=obj.recv(1024)
r=str(ret,encoding='utf-8')
if r=='y':
return 1
else:
return 0
def before(usrname,pwd):
'''
选择登陆或注册,展示用户的详细目录信息,支持cd和ls命令
:return:
'''
a=input('请选择1.登陆 2.注册')
obj.sendall(bytes(a,encoding='utf-8'))
obj.recv(1024)
if a=='':
ret=login(usrname,pwd)
if ret:
print('登陆成功')
return 1
else:
print('用户名或密码错误')
return 0
elif a=='':
ret=regist(usrname,pwd)
if ret:
print('注册成功')
return 1
else:
print('用户名已存在')
return 0
def usr_file(usrname):
obj.sendall(bytes('打印用户文件路径',encoding='utf-8'))
ret=obj.recv(1024) #等待客户端发送
r=str(ret,encoding='utf-8')
print(r)
while True:
a=input('输入cd切换目录,ls查看目录详细信息,q退出>:') obj.sendall(bytes(a,encoding='utf-8'))
if a=='q':
break
else:
ret=obj.recv(1024) #等待客户端发送
r=str(ret,encoding='utf-8')
if len(r)==1:#判断是cd结果还是ls的结果(ls只有一个子目录也可以直接打印)
print(r)
else:
li=r.split(',')
for i in li:
print(i) #打印每一个子目录 def main(usrname,pwd):
ret=obj.recv(1024) #等待客户端发送
r=str(ret,encoding='utf-8')
print(r)
result=before(usrname,pwd)#登陆或注册
if result:
usr_file(usrname)
while True:
a=input('请选择1.传文件 2.执行命令 q退出:')
obj.sendall(bytes(str(a),encoding='utf-8'))
ret=obj.recv(1024) #确认是否收到a
r=str(ret,encoding='utf-8')
print(r)
if a=='':
b=input('请输入文件路径(测试版路径为:f.png):')
# b='f.png'
if os.path.exists(b):
send_file(b)
obj.sendall(bytes('hhe',encoding='utf-8'))
# obj.recv(1024)
elif a=='':
b=input('请输入command:')
command(b)
elif a=='q':
break
else:
print('输入错误') obj.close() if __name__ == '__main__':
obj=socket.socket() #创建客户端socket对象
obj.connect(('127.0.0.1',9999))
usrname=input('请输入用户名')
pwd=input('请输入密码')
main(usrname,pwd)
  

第五十六节,python实现支持并发、断点续传的Ftp程序的更多相关文章

  1. 第三百五十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy分布式爬虫要点

    第三百五十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy分布式爬虫要点 1.分布式爬虫原理 2.分布式爬虫优点 3.分布式爬虫需要解决的问题

  2. 第一百五十六节,封装库--JavaScript,延迟加载

    封装库--JavaScript,延迟加载 延迟加载的好处,就是在浏览器视窗外的图片,不加载,拖动鼠标到浏览器视窗内后加载,用户不看的图片就不用加载,可以减少服务器大量流量 将图片的src地址用一张统一 ...

  3. 第三百六十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的bool组合查询

    第三百六十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的bool组合查询 bool查询说明 filter:[],字段的过滤,不参与打分must:[] ...

  4. 第三百五十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)介绍以及安装

    第三百五十九节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)介绍以及安装 elasticsearch(搜索引擎)介绍 ElasticSearch是一个基于 ...

  5. 第三百五十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—数据收集(Stats Collection)

    第三百五十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—数据收集(Stats Collection) Scrapy提供了方便的收集数据的机制.数据以key/value方式存储,值大多是计数 ...

  6. 第三百四十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—Requests请求和Response响应介绍

    第三百四十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—Requests请求和Response响应介绍 Requests请求 Requests请求就是我们在爬虫文件写的Requests() ...

  7. 【Visual C++】游戏开发五十六 浅墨DirectX教程二十三 打造游戏GUI界面(一)

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/16384009 作者:毛星云 ...

  8. 第一百二十六节,JavaScript,XPath操作xml节点

    第一百二十六节,JavaScript,XPath操作xml节点 学习要点: 1.IE中的XPath 2.W3C中的XPath 3.XPath跨浏览器兼容 XPath是一种节点查找手段,对比之前使用标准 ...

  9. 第四百一十六节,Tensorflow简介与安装

    第四百一十六节,Tensorflow简介与安装 TensorFlow是什么 Tensorflow是一个Google开发的第二代机器学习系统,克服了第一代系统DistBelief仅能开发神经网络算法.难 ...

随机推荐

  1. UITabelview的删除

    删除的效果 Automatic Bottom Fade left middle none right top 简单删除 先删除数据源里的数据,然后再删除cell,否者会报错 let indexPath ...

  2. Product Management vs. Product Marketing

    Posted by Marty Cagan on August 28, 2007 Tags: product management, product marketing, program manage ...

  3. CMD常用指令

    列出所有端口使用情况 netstat -ano 只查看端口5060使用情况 netstat -ano|findstr "5060" 查看进程8612的信息 tasklist|fin ...

  4. gridview动态添加行(不用datatable实现)

    GridViewRow newrow = , , DataControlRowType.Separator, DataControlRowState.Normal); TableCell[] tc=] ...

  5. IOS开发自定义tableviewcell的注意点😄

    自定义tableviewcell 1.xib,nib拖控件:awakefromnib: 设置2,不拖控件:- (instancetype)initWithStyle:(UITableViewCellS ...

  6. shrio初体验(2)Realm

    Realm:域,Shiro从从Realm获取安全数据(如用户.角色.权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法:也需 ...

  7. request获取ip

    public static String getIp(HttpServletRequest request) { String ip = request.getHeader("x-forwa ...

  8. hdu 3669 Cross the Wall(斜率优化DP)

    题目连接:hdu 3669 Cross the Wall 题意: 现在有一面无限大的墙,现在有n个人,每个人都能看成一个矩形,宽是w,高是h,现在这n个人要通过这面墙,现在只能让你挖k个洞,每个洞不能 ...

  9. 页面加载与iframe加载函数

    <head> <script> $(document).ready(function(){ alert("a");   var wait = documen ...

  10. android教学大纲

    android班 教学大纲 个小时 次课:Android开发环境搭建及工具介绍 Android系统简介 Android开发环境简介及搭建 AndroidStudio提供的工具组件 次课:第一个Andr ...