目录

1.FTP程序所需要的知识点

2.FTP程序具体实现过程

  2.1 FTP程序之注册功能

  2.2 FTP程序之登录功能

  2.3 FTP程序之下载功能

3.FTP程序源代码

FTP程序所需要的知识点

1.socketserver并发编程

2.连续send,recv黏包现象:struct

3.hashlib模块的md5加密

4.静态方法staticmethod和类方法classmethod

5.json序列化

6.反射:hasattr,setattr

7.os模块相关方法

FTP程序具体实现过程

FTP程序之注册功能

1.要明确,FTP程序是要实现服务端的并发的,所以需要引入socketserver模块来实现并发

2.写服务端下socketserver的基本语法[day31:socketserver的基本语法]

# 服务端
import socketserver class FTPServer(socketserver.BaseRequestHandler):
def handle(self):
pass myserver = socketserver.ThreadingTCPServer(("127.0.0.1",9000),FTPServer)
myserver.serve_forever() # 客户端
import socket
sk = socket.socket()
sk.connect(("127.0.0.1",9000)) sk.close()

3.用户需要自己输入账号和密码,所以在客户端需要写输入用户名和密码的方法(输入用户名和密码后,发送给服务端)

4.在客户端定义auth方法,先写两个input输入用户名和密码

5.输入完用户名密码之后,怎样将用户信息传给服务端呢?

将用户名和密码以及操作做成一个字典,并用json序列化成字符串,并encode后,使用sk.send()发送给服务端

这部分的具体代码如下所示:

# 客户端
def auth(opt):
usr = input("username:").strip()
pwd = input("password:").strip()
dic = {"user":usr,"passwd":pwd,"operate":opt}
str_dic = json.dumps(dic) # 将字典序列化成字符串
sk.send(str_dic.encode()) # 将字符串转化成字节流并发送出去 auth("register")

6.服务端已经将用户名密码和操作发过去了,所以现在服务端需要接收一下,服务端的整体逻辑写在类中的handle方法中

再定义一个专门用来接收的方法myrecv,并使用handle方法去调用myrecv方法

这部分的具体代码如下所示:

# 服务端
class FTPServer(socketserver.BaseRequestHandler):
def handle(self):
opt_dic = self.myrecv()
print(opt_dic) def myrecv(self):
info = self.request.recv(1024)
opt_str = info.decode()
opt_dic = json.loads(opt_str)
return opt_dic

通过以上步骤,我们实现了一収一发

7.接收到了客户端发来的数据,我们就可以在服务端写一些关于注册的逻辑了

在服务端定义Auth类,专门用来实现注册登录,在handler方法也可以去调用类中的成员

那么Auth类中应该写什么呢?

1.首先在当前目录创建db文件夹,并在db问文件夹中创建userinfo.txt用来存放用户名和密码

2.对密码使用md5加密

8.在Auth类中定义md5方法,用来对密码进行一个加密操作

# 服务端
class Auth():
def md5(usr,pwd):
md5_obj = hashlib.md5(usr.encode())
md5_obj.update(pwd.encode())
return md5_obj.hexdigest()

我们先加密一份数据存放到userinfo.txt中

9.现在已经对每个用户名的密码加密了,但是还有一个问题需要考虑,在注册的时候,不能注册已经存在的用户名,所以需要对用户名进行判断

10.定义register方法,并使用classmethod装饰器,当其他类调用register方法时,会自动传递类参数.

11.拼接出一个userinfo所在文件的完整路径

1.首先获取当前文件(server.py)所在的位置

两种方法:

  方法一:os.getcwd()

  方法二:os.path.dirname(__file__)

print(os.getcwd()) # F:\OldBoyPython\week6\day36
print(__file__) # F:/OldBoyPython/week6/day36/ceshi.py
print(os.path.dirname(__file__)) # F:/OldBoyPython/week6/day36

2.使用os.path.join进行路径拼接

base_path = os.getcwd()
userinfo = os.path.join(base_path,"db","userinfo.txt")
print(userinfo) # F:\OldBoyPython\week6\day36\db\userinfo.txt

这样,我们就获取到了userinfo.txt的绝对路径了

12.当有了userinfo.txt的绝对路径后,我们就可以开始文件操作了

在第9步,我们说到要检测用户名是否存在,现在我们就可以实现了

当用户名存在时,返回一个状态False和一个用户名已存在信息提示

@classmethod
def register(cls, opt_dic):
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": "用户名存在了"}

13.用户名存在的逻辑已经写完,接下来就是用户名可以使用的逻辑

要注意:密码需要加密后再写入

with open(userinfo, mode='a+', encoding='utf-8') as fp:
# 账号就是字典的账号,密码使用md5加密处理后再写入文件
strvar = "%s:%s\n" % (opt_dic["user"], cls.md5(opt_dic["user"], opt_dic["passwd"]))
fp.write(strvar)

如果登录成功了,返回一个状态True和一个注册成功信息提示

到此,注册部分的逻辑就已经写完了,具体代码如下所示:

@classmethod
def register(cls, opt_dic):
# 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:
# 账号就是字典的账号,密码使用md5加密处理后再写入文件
strvar = "%s:%s\n" % (opt_dic["user"], cls.md5(opt_dic["user"], opt_dic["passwd"]))
fp.write(strvar) # 3.返回一个注册成功的状态
return {"result": True, "info": "注册成功"}

14.注册的register方法已经写完,但是现在我们需要将register方法和下面的FTPServer类建立联系,这个时候就需要使用反射来实现了

换句话来说:就是想在FTPServer的handle方法中使用Auth中的register方法

15.构建出反射,代码如下所示

到目前为止,基本的代码已经实现,现进行测试,代码如下所示

# 服务端
import socketserver
import json
import hashlib
import os # 找当前数据库文件所在的绝对路径
base_path = os.getcwd()
# F:\OldBoyPython\week6\day36\db\userinfo.txt
userinfo = os.path.join(base_path,"db","userinfo.txt") 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):
# 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:
# 账号就是字典的账号,密码使用md5加密处理后再写入文件
strvar = "%s:%s\n" % (opt_dic["user"],cls.md5(opt_dic["user"],opt_dic["passwd"]))
fp.write(strvar) # 3.返回一个注册成功的状态
return {"result":True,"info":"注册成功"} class FTPServer(socketserver.BaseRequestHandler):
def handle(self):
opt_dic = self.myrecv()
print(opt_dic)
if hasattr(Auth,"register"):
res = getattr(Auth,"register")(opt_dic)
print(res) def myrecv(self):
info = self.request.recv(1024)
opt_str = info.decode()
opt_dic = json.loads(opt_str)
return opt_dic myserver = socketserver.ThreadingTCPServer(("127.0.0.1",9000),FTPServer)
myserver.serve_forever()
# 客户端
import socket
import json sk = socket.socket()
sk.connect(("127.0.0.1",9000)) # 处理収发数据的逻辑
def auth(opt):
usr = input("username:").strip()
pwd = input("password:").strip()
dic = {"user":usr,"passwd":pwd,"operate":opt}
str_dic = json.dumps(dic) # 将字典序列化成字符串
sk.send(str_dic.encode()) # 将字符串转化成字节流并发送出去 auth("register") sk.close()

运行结果如下图所示

客户端输入用户名和密码

服务端接收到客户端发来的数据

并且userinfo.txt也已经写入了你刚才在客户端输入的用户名和密码

16.在服务端我们可以看到注册成功/注册失败的信息了,现在我们想把这个信息发回给客户端,在客户端也能显示出来

和服务端的myrecv方法一样,我们需要自定义一个接収方法mysend

既然在服务端发数据,当然要在客户端接收数据

好的,到此第一部分注册功能就全部完成了。让我们看一下运行结果

所有的信息都应该是显示在客户端上的

FTP程序之登录功能

1.现在添加了登录功能,所以反射的时候就要动态起来。

2.Auth类中只有注册和登录两个方法,如果用户在客户端传入其他方法,必须要给予错误的提示

下面,我们来测试一下结果

3.现在就可以开始写登录函数的逻辑了。。。

登录嘛,肯定是要验证用户名和密码的,所以肯定需要从userinfo.txt中取出用户名和密码进行比对

所以先进行文件操作,将用户名和密码取出来,在进行验证

@ classmethod
def login(cls,opt_dic):
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["passwd"]):
return {"result":True,"info":"登陆成功"} return {"result":False,"info":"登录失败"}

其他的部分都不用改,定义了login函数,FTPServer就会自己识别是什么操作,并且通过反射获取到对应方法的返回值,将返回值发送给客户端,然后客户端接收后,打印出来

运行结果如下图所示

4.到此,登录部分的逻辑也已经完成了!!

但是在客户端调用时,还是非常死板的

这种调用方式非常的lowb,所以需要改进一下。。

我们需要搞一个界面。

5.先在客户端定义login函数和register函数,在函数里进行调用。

6.除了登录和注册函数,还需要搞一个退出的功能

在客户端定义myexit函数,用来实现退出的功能

现在我们在客户端已经定义了退出函数,但是在服务端我们也要让服务端知道退出的状态。

我们在客户端发送了一个opt_dic给服务端,然后服务端接收这个opt_dic

到此,退出功能就已经实现完了。

7.现在我们需要把登录,注册和退出形成一套界面

def main():
# 生成菜单界面
for i,tup in enumerate(operate_lst,start=1):
print(i,tup[0]) # 输入相应序号,实现对应操作
num = int(input("请选择您要进行的操作>>>"))
res = operate_lst[num-1][1]()
return res # 将对应操作的返回值返回出来 while True:
res = main() # 调用main获取到对应的返回值
print(res)

在客户端我们可以通过while True实现循环调用main,进而可以进行循环登录注册和退出。

那么在服务端我们也应该是循环进行调用注册登录和退出

所以需要在服务端也加上一个while True

8.到此为止,登录,注册和退出的功能就都已经实现了。

代码如下所示

# 服务端
import socketserver
import json
import hashlib
import os # 找当前数据库文件所在的绝对路径
base_path = os.path.dirname(__file__)
# /mnt/hgfs/python31_gx/day36/db/userinfo.txt
userinfo = os.path.join(base_path,"db","userinfo.txt") 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):
# 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:
strvar = "%s:%s\n" % ( opt_dic["user"] , cls.md5( opt_dic["user"],opt_dic["passwd"] ) )
fp.write(strvar) """
当用户上传的时候,给他创建一个专属文件夹,存放数据
""" # 3.返回状态
return {"result":True,"info":"注册成功"} @classmethod
def login(cls,opt_dic):
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["passwd"] ) :
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) # {'user': 'wangwen', 'passwd': '111', 'operate': 'register'}
if hasattr(Auth,opt_dic["operate"]):
# print( getattr(Auth,"register") )
res = getattr(Auth,opt_dic["operate"])(opt_dic) # login(opt_dic) # 如果接受的操作是myexit,代表退出
if res["result"] == "myexit":
return # 把注册的状态发送给客户端
self.mysend(res)
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):
send_info = json.dumps(send_info).encode()
self.request.send(send_info) # 设置一个端口可以绑定多个程序
# socketserver.TCPServer.allow_reuse_address = True
myserver = socketserver.ThreadingTCPServer( ("127.0.0.1",9000) , FTPServer)
myserver.serve_forever()
# ### 客户端
import socket
import json
""""""
sk = socket.socket()
sk.connect( ("127.0.0.1",9000) ) # 处理收发数据的逻辑
def auth(opt):
usr = input("username: ").strip()
pwd = input("password: ").strip()
dic = {"user":usr,"passwd":pwd,"operate":opt}
str_dic = json.dumps(dic)
# 发送数据
sk.send(str_dic.encode("utf-8")) # 接受服务端响应的数据
file_info = sk.recv(1024).decode()
file_dic = json.loads(file_info)
return file_dic # 注册
def register():
res = auth("register")
return res # 登录
def login():
res = auth("login")
return res # 退出
def myexit():
opt_dic = {"operate":"myexit"}
sk.send(json.dumps(opt_dic).encode())
exit("欢迎下次再来") # 第一套操作界面
# 0 1 2
operate_lst1 = [ ("登录",login) ,("注册",register) , ("退出",myexit) ] """
1.登录
2.注册
3.退出 1 ('登录', <function login at 0x7ff7cf171a60>)
2 ('注册', <function register at 0x7ff7cf17e620>)
3 ('退出', <function myexit at 0x7ff7cf171ae8>)
""" def main():
for i,tup in enumerate(operate_lst1,start=1):
print(i , tup[0])
num = int(input("请选择执行的操作>>> ").strip()) # 1 2 3
# 调用函数
# print(operate_lst1[num-1]) ('退出', <function myexit at 0x7f801e34aa60>)
# print(operate_lst1[num-1][1]) <function myexit at 0x7f801e34aa60>
# operate_lst1[num-1][1]() myexit()
res = operate_lst1[num-1][1]()
return res while True:
# 开启第一套操作界面
res = main()
print(res) sk.close()

执行结果如下图所示

FTP注册之下载功能

1.当你登录成功后,要跳转到另一套界面,让用户选择下载上传还是退出

所以我们需要像登录注册退出那套界面逻辑一样,再搞一个operate_lst2

只有登录成功的时候,才能出现第二套界面。

2.客户端现在已经发送过去了,那么对应的服务端也应该有所接收

3.download我们后面再说,先把界面2的退出搞定

同理,客户端的myexit有exit()直接终止程序,在服务端也要及时终止程序

直接搞上一个return,连循环加函数全都退出

到此,界面2的退出也已经搞定了,接下来就搞最复杂的download

4.下载,先搞一下这个客户端

在客户端定义一个download方法,定义一个字典,字典里写入操作和下载的文件名

5.客户端定义了下载方法将字典发送过去,服务端也应该定义download下载方法来接收这个字典并进行逻辑操作

# 服务端
def download(self, opt_dic):
filename = opt_dic["filename"] # 获取用户在客户端输入的文件名
file_abs = os.path.join(base_path, "video", filename) # 获取到要下载视频的绝对路径
if os.path.exists(file_abs): # 如果文件存在
dic = {"result": True, "info": "文件存在,可以下载"}
self.mysend()
else: # 如果文件不存在
pass

6.如果文件存在可以下载,那么就可以执行下载的流程了

在下载时,服务端需要将视频发送给客户端,因为视频很大,且需要分段发送,所以可能会存在黏包现象。

所以需要引入struct模块,并改造mysend方法,以解决黏包现象

# 服务端
def mysend(self, send_info, sign=False):
send_info = json.dumps(send_info).encode()
if sign:
# 1.发送数据的长度
res = struct.pack("i", len(send_info))
self.request.send(res)
# 2.发送真实的数据
self.request.send(send_info)
# 客户端
def myrecv(info_len=1024,sign=False):
if sign:
# 1.接受数据的长度
info_len = sk.recv(4)
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

7.客户端向服务端发送下载操作和要下载的文件名,服务端接收到文件名称,返回一个可以下载的状态给客户端

8.刚才服务端已经将文件存在,可以下载的提示信息发给客户端了,接下来服务端要发送客户端要下载的视频的文件名字和文件大小

9.现在该发的都发了,最后一步就是发送真实的内容了

10.现在几乎是已经大功告成了,还差最后一点小瑕疵

登录功能的第7步,我们说到,要想进行循环操作(循环选择下载上传和退出),需要在客户端和服务端加while True

11.到此!!所有功能实现完毕

运行结果如下图所示

这个时候,我们去download文件夹,可以查看到下载的视频

FTP程序源代码

客户端

# 客户端
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:
info_len = sk.recv(4)
info_len = struct.unpack("i",info_len)[0] file_info = sk.recv(info_len).decode()
file_dic = json.loads(file_info)
return file_dic # 处理収发数据的逻辑
def auth(opt):
usr = input("username:").strip()
pwd = input("password:").strip()
dic = {"user":usr,"passwd":pwd,"operate":opt}
str_dic = json.dumps(dic) # 将字典序列化成字符串
sk.send(str_dic.encode()) # 将字符串转化成字节流并发送出去
return myrecv() def login():
res = auth("login")
return res def register():
res = auth("register")
return res def myexit():
opt_dic = {"operate":"myexit"}
sk.send(json.dumps(opt_dic).encode())
exit("欢迎下次再来") def download():
operate_dict = {
"operate":"download",
"filename":"ceshi123.mp4"
}
# 把要下载的文件名称传递给服务端
operate_str = json.dumps(operate_dict)
sk.send(operate_str.encode("utf-8")) # 接受服务端发过来的数据(是否可以操作)
res = myrecv(sign=True)
print(res) # 1.如果收到了服务端的可以下载的提示,就创建一个文件夹用来存放下载的视频
if res["result"]:
try:
os.mkdir("mydownload")
except:
pass
else:
print("没有该文件")
# 2.接受文件名字和文件大小
dic = myrecv(sign=True)
print(dic)
# 3.接収真实的文件
with open("./mydownload/" + dic["filename"],mode='wb') as fp:
while dic["filesize"]:
content = sk.recv(102400)
fp.write(content)
dic["filesize"] -= len(content)
print("客户端下载完毕") operate_lst1 = [("注册",register),
("登录",login),
("退出",myexit)]
operate_lst2 = [("下载",download),
("退出",myexit)] def main(operate_lst):
for i,tup in enumerate(operate_lst,start=1):
print(i,tup[0]) num = int(input("请选择您要进行的操作>>>"))
res = operate_lst[num-1][1]()
return res while True:
res = main(operate_lst1)
if res["result"]:
while True:
res = main(operate_lst2) sk.close()

服务端

# 服务端
import socketserver
import json
import hashlib
import os
import struct # 找当前数据库文件所在的绝对路径
base_path = os.getcwd()
# F:\OldBoyPython\week6\day36\db\userinfo.txt
userinfo = os.path.join(base_path,"db","userinfo.txt") 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):
# 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:
# 账号就是字典的账号,密码使用md5加密处理后再写入文件
strvar = "%s:%s\n" % (opt_dic["user"],cls.md5(opt_dic["user"],opt_dic["passwd"]))
fp.write(strvar) # 3.返回一个注册成功的状态
return {"result":True,"info":"注册成功"} @ classmethod
def login(cls,opt_dic):
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["passwd"]):
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) # {'user': 'libolun', 'passwd': '111', 'operate': 'register'}
if hasattr(Auth,opt_dic["operate"]):
res = getattr(Auth,opt_dic["operate"])(opt_dic)
if res["result"] == "myexit":
return
self.mysend(res) if res["result"]: # 接受界面2数据
while True:
opt_dic = self.myrecv()
print(opt_dic) if opt_dic["operate"] == "myexit":
return if hasattr(self,opt_dic["operate"]):
getattr(self,opt_dic["operate"])(opt_dic) 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:
res = struct.pack("i",len(send_info))
self.request.send(res)
self.request.send(send_info) def download(self,opt_dic):
filename = opt_dic["filename"] # 获取用户在客户端输入的文件名
file_abs = os.path.join(base_path,"video",filename) # 获取到要下载视频的绝对路径
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:
content = fp.read(102400)
self.request.send(content)
filesize -= len(content)
print("服务器下载完毕")
else:
dic = {"result":False,"info":"文件不存在"}
self.mysend(dic,sign=True) myserver = socketserver.ThreadingTCPServer(("127.0.0.1",9000),FTPServer)
myserver.serve_forever()

小程序5:FTP程序的更多相关文章

  1. Python开发程序:FTP程序

    作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp se ...

  2. 用python开发简单ftp程序

    根据alex老师视频开发的简单ftp程序,只能实现简单的get功能 ftp客户端程序: #!/usr/bin/env python #_*_ coding:utf-8 _*_ import socke ...

  3. python实现FTP程序

    python实现FTP程序 程序源码 上传功能 查看文件 cd功能 创建目录 程序源码 目录结构 服务端 主程序 import optparse import socketserver import ...

  4. Python3学习之路~8.6 开发一个支持多用户在线的FTP程序-代码实现

    作业: 开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ...

  5. (转)Python开发程序:支持多用户在线的FTP程序

    原文链接:http://www.itnose.net/detail/6642756.html 作业:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ...

  6. gevent协程、select IO多路复用、socketserver模块 改造多用户FTP程序例子

    原多线程版FTP程序:http://www.cnblogs.com/linzetong/p/8290378.html 只需要在原来的代码基础上稍作修改: 一.gevent协程版本 1. 导入geven ...

  7. 多用户在线FTP程序

    项目名:多用户在线FTP程序 一.需求 1.用户加密认证 2.允许同时多用户登录 3.每个用户有自己的家目录 ,且只能访问自己的家目录 4.对用户进行磁盘配额,每个用户的可用空间不同 5.允许用户在f ...

  8. [ python ] 项目一:FTP程序

    声明: 该项目参考学习地址: http://www.cnblogs.com/lianzhilei/p/5869205.html , 感谢博主分享,如有侵权,立即删除. 作业:开发一个支持多用户在线的F ...

  9. 老男孩python作业7-开发一个支持多用户在线的FTP程序

    作业6:开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ...

随机推荐

  1. Redis之Redis的数据类型

    ​1.Redis的数据类型     Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(无序集合)及ZSet(有序集合)  2.String(字符串)    ...

  2. 初学用记事本运行java报错:找不到或无法加载主类解决方法,部分出错解决办法

    刚开始学习java的人第一个程序可能通过记事本运行,当中间可能会会出现各种错误,我在下面间可能解决出现的问题 1. java环境变量没有安装好 以我的win10系统为例,在装好相应的jdk后,环境变量 ...

  3. python基础day7_编码及小数据池

    数字概念,字符串----小数据池 数字的范围:-5---256 字符串: 1,不能有特殊字符 2,s*20还是同一个地址,s*21之后就是另外一个地址 i1 = 6 i2 = 6 print(id(i ...

  4. Python os.renames() 方法

    概述 os.renames() 方法用于递归重命名目录或文件.类似rename().高佣联盟 www.cgewang.com 语法 renames()方法语法格式如下: os.renames(old, ...

  5. 使用jsdelivr + GitHub + PicGo搭建免费图床

    前言 之前一直有开通有道云笔记会员,主要是为了会员markdown图片可以在线保存的功能,前一阵子会员到期,考虑这个功能可不可以自己单独实现,从而替代使用有道云会员. 通过网上搜索的方式,查询到了几种 ...

  6. 算法图解(python2.7)高清PDF电子书

    点击获取提取码:pzhb 内容简介 本书示例丰富,图文并茂,以让人容易理解的方式阐释了算法,旨在帮助程序员在日常项目中更好地发挥算法的能量.书中的前三章将帮助你打下基础,带你学习二分查找.大O表示法. ...

  7. Docker入坑指南之EXEC

    容器启动之后,如果我们需要进入容器内修改配置,比如mysql修改启动配置 我们启动的附加参数是不是shell,这个时候就可以用docker exec了,docker除了对image参数以外,大部分命令 ...

  8. 3月28日考试 题解(二分答案+树形DP+数学(高精))

    前言:考试挂了很多分,难受…… --------------------- T1:防御 题意简述:给一条长度为$n$的序列,第$i$个数的值为$a[i]$.现让你将序列分成$m$段,且让和最小的一段尽 ...

  9. 改变对象的字符串显示__str__repr

    改变对象的字符串显示 # l=list('hello') # # print(l) # file=open('test.txt','w') # print(file) class Foo: def _ ...

  10. Android 给服务器发送网络请求

    今天听得有点蒙,因为服务器的问题,这边建立服务器的话,学长用的是Idea建立的Spring之类的方法去搞服务器. 然后就是用Android去给这个服务器发送请求,大致效果还是懂的,就是像网站发送请求, ...