基于socketsever下实现的FTP
# ### 客户端client
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) #
# unpack 返回的是元组(1999,)
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):
"""
opt: login 登录 or register 注册
"""
usr = input("username: ").strip()
pwd = input("password: ").strip()
dic = {"user":usr,"pwd":pwd,"operate":opt}
str_dic = json.dumps(dic)
# 把数据发送给服务端
sk.send(str_dic.encode())
return myrecv() # 1.注册
# res = auth("register")
# print(res) def register():
res = auth("register")
return res # 2.登录
# res = auth("login")
# print(res)
def login():
res = auth("login")
return res # 3.退出
def myexit():
opt_dic = {"operate":"myexit"}
sk.send(json.dumps(opt_dic).encode())
exit("欢迎下次再来 ... ")
# myexit() # 4.下载
def download():
operate_dict = {
"operate":"download",
"filename":"ceshivideo.mp4"
} opt_str = json.dumps(operate_dict)
sk.send(opt_str.encode("utf-8")) # (1) 为了避免黏包,接受两次数据
res = myrecv(sign=True)
print(res) # {'result': True, 'info': '改文件存在'}
if res["result"]:
# 创建文件夹
try:
os.mkdir("mydownload")
except:
pass # (2) 接受文件名字 和 文件大小
dic = myrecv(sign=True)
print(dic,"<2>") # {'filename': 'ceshivideo.mp4', 'filesize': 54822153} <2> # (3) 接受文件数据
with open("./mydownload/" + dic["filename"],mode="wb") as fp:
while dic["filesize"]:
content = sk.recv(1024)
fp.write(content)
dic["filesize"] -= len(content)
print("客户端下载完毕")
else:
print("文件不存在") # 第一套界面
operate_lst1 = [ ("登录",login) , ("注册",register) ,("退出",myexit)]
# 第二套界面
operate_lst2 = [("下载",download),("退出",myexit)]
"""
( 1, ('登录', <function login at 0x00000234890402F0>) )
(2, ('注册', <function register at 0x0000023489040268>))
(3, ('退出', <function myexit at 0x0000023489040378>))
"""
def main(operate_lst):
for i,tup in enumerate(operate_lst,start=1):
print(i,tup[0]) num = int(input("请选择要执行的号码:>>>").strip())
# 调用函数
res = operate_lst[num-1][1]() # login()
# 返回结果
return res # 循环调用1号操作界面
while True:
# 开启第一套操作界面
res = main(operate_lst1)
print(res)
# 开启第二套操作界面
if res["result"]:
while True:
res = main(operate_lst2)
print(res) sk.close()
# ### 服务端 server
import socketserver
import json
import os
import hashlib
import struct # print(os.getcwd())
print(__file__)
print(os.path.dirname(__file__))
base_path = os.path.dirname(__file__) # 获取当前账户文件所在的完整绝对路径
userinfo = os.path.join(base_path,"db","userinfo.txt")
print(userinfo)
""""""
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) :
# opt_dic = {'user': 'lisi', 'pwd': '222', 'operate': 'register'}
# 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:
# 用户名:密码 换行
fp.write("%s:%s\n" % (opt_dic["user"] , cls.md5(opt_dic["user"],opt_dic["pwd"]))) """
当用户上传文件的时候,动态给用户创建文件夹
""" # 3.直接返回对应的状态
return {"result":True,"info":"注册成功"} # 登录
@classmethod
def login(cls,opt_dic):
# opt_dic = {'user': 'lisi', 'pwd': '222', 'operate': 'register'}
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["pwd"]):
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) # 判断类当中是否含有register这个方法,如果有就反射
if hasattr(Auth,opt_dic["operate"]):
# getattr 反射出对应的register函数
res = getattr(Auth,opt_dic["operate"])(opt_dic) # 判断是myexit,代表退出
if res["result"] == "myexit":
return # 把返回值发送给客户端
self.mysend(res) # 等待处理用户第二套操作界面的逻辑
if res["result"]:
while True:
opt_dic = self.myrecv()
print(opt_dic) # 如果operate接受的是myexit 直接终止handle函数;
if opt_dic["operate"] == "myexit":
return # 可以反射 类 或者 对象 或者 模块响应的属性和方法
if hasattr(self,opt_dic["operate"]):
getattr(self,opt_dic["operate"])(opt_dic) # 如果Auth当中没有该操作的应急处理
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:
# 通过pack转化成居右固定4个字节长度的字节流
res = struct.pack("i",len(send_info))
# 把接下来要发送的数据长度发送给客户端
self.request.send(res) # # 发送出去
self.request.send(send_info) # # 下载方法
def download(self,opt_dic):
# {'operate': 'download', 'filename': 'ceshivideo.mp4'}
# print(opt_dic)
# 先判断是否存在该文件
filename = opt_dic["filename"]
file_abs = os.path.join(base_path,"myvideo",filename)
# print(filename) # ceshivideo.mp4
# print(file_abs) # D:/gongxiang8/day31/ftp\myvideo\ceshivideo.mp4 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:
# 一次性最多读取1024个字节
content = fp.read(1024)
self.request.send(content)
filesize -= len(content)
print("服务器下载完毕") else:
dic = {"result":False,"info":"改文件不存在"}
self.mysend(dic,True) myserver = socketserver.ThreadingTCPServer( ("127.0.0.1" , 9000) , FTPServer)
# 让一个端口绑定多个程序(测试时使用)
socketserver.TCPServer.allow_reuse_address = True
myserver.serve_forever()
基于socketsever下实现的FTP的更多相关文章
- 技术的正宗与野路子 c#, AOP动态代理实现动态权限控制(一) 探索基于.NET下实现一句话木马之asmx篇 asp.net core 系列 9 环境(Development、Staging 、Production)
黄衫女子的武功似乎与周芷若乃是一路,飘忽灵动,变幻无方,但举手抬足之间却是正而不邪,如说周芷若形似鬼魅,那黄衫女子便是态拟神仙. 这段描写出自<倚天屠龙记>第三十八回. “九阴神抓”本是& ...
- 基于SourceTree 下的 Git Flow 模型
基于SourceTree 下的 Git Flow 模型 1. sourceTree 是一个开源的git 图形管理工具,可下载mac版本,windows版本 2. Git Flow 是一套使用Git进 ...
- 基于SpringMVC下的Rest服务框架搭建【1、集成Swagger】
基于SpringMVC下的Rest服务框架搭建[1.集成Swagger] 1.需求背景 SpringMVC本身就可以开发出基于rest风格的服务,通过简单的配置,即可快速开发出一个可供客户端调用的re ...
- 团队软件开发_基于windows下截屏软件关于NABC框架的特点
经过我们小组数次的激烈讨论,就自己的能力和时间而言,我们小组的初步的计划是开发一款基于windows下的截图软件. 关于这个软件的功能,我们初步的想法如下: 1.能在windows下后台运行,有相应的 ...
- 1 Linux平台下快速搭建FTP服务器 win7下如何建立ftp服务器
百度经验连接(亲测可用) http://jingyan.baidu.com/article/380abd0a77ae041d90192cf4.html win7下如何建立ftp服务器 http://j ...
- Linux下如何进行FTP安装与设置
1. 先用rpm -qa| grep vsftpd命令检查是否已经安装,如果ftp没有安装,使用yum -y install vsftpd 安装,(ubuntu 下使用apt-get instal ...
- 基于定位下拉框或者需要点击link才显示的下拉框,二次定位与多次定位实现的实际效果区别
还是基于上次那个练习的后续出现的思考,http://www.cnblogs.com/8013-cmf/p/6555790.html 界面: 源码: 写法如下: 继续解释这两种的区别: 1.其实基于定 ...
- 基于Windows下处理Java错误:编码GBK的不可映射字符的解决方案
基于Windows下处理Java错误:编码GBK的不可映射字符的解决方案 最近在研究Java,涉及命令行编译,使用notepad++编辑器,然后使用javac编译: 之前的几个文件没有中文的内容,都没 ...
- 基于Windows下浏览器无法正常打开的解决方案
Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE /* Style Definitions */ table.MsoNormalTable ...
随机推荐
- 你看不懂的spring原理是因为不知道这几个概念
背景 问题从一杯咖啡开始. 今天我去楼下咖啡机买了一杯「粉黛拿铁」.制作过程中显示: 我取了做好的粉黛拿铁,喝了一口,果然就是一杯热巧克力.咦咦咦,说好的拿铁呢?虽然我对「零点吧」的咖啡评价很高,觉得 ...
- OpenCV:增加和减少图像的亮度,图像的加减法
首先导包: import numpy as np import cv2 import matplotlib.pyplot as plt def show(image): plt.imshow(imag ...
- Command CompileSwiftSources failed with a nonzero exit code
Xcode错误提示:Command CompileSwiftSources failed with a nonzero exit code,网上找了好多才搞定,通过在Build Setting里面自添 ...
- Flask框架后端开发常见错误处理
1.ValueError: urls must start with a leading slash 这个错误原因可能发生在所有路由相关地方,少加了一个'/'造成的. 2.ImportError: c ...
- Memcached 基本语法 记录
set 命令:命令将value数值存储在指定的key中: set key flags exptime bytes [noreply] value key:键值 key-value 结构中的 key,用 ...
- Linux系统学习 五、网络基础—网络通信协议
OSI/ISO七层模型和TCP/IP四层模型 网络层协议和IP划分 OSI的七层框架 物理层:设备之间的比特流的传输.物理接口.电气特性等. 数据链路层:成帧.用MAC地址访问媒介.错误检测与修正. ...
- springboot入门以及配置文件
springboot入门以及配置文件 SpringBoot是什么? Spring Boot它本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速.敏捷地开发新一代基于Spring框架的应用 ...
- springmvc的文件上传和JWT图形验证码
相关pom依赖 <dependency> <groupId>commons-fileupload</groupId> <artifactId>commo ...
- Day14 - Python基础14 事件驱动模型、IO模型
本节内容: 1:事件驱动模型 2:IO模型前戏准备 3:4种IO模型 1:事件驱动模型 传统的编程是如下线性模式的: 开始--->代码块A--->代码块B--->代码块C---> ...
- acwing 76. 和为S的连续正数序列
地址 https://www.acwing.com/problem/content/description/72/ 输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数). 例如输入15,由 ...