需求分析:
(1)分为服务器和客户端,要求可以有多个客户端同时 *** 作
(2)客户端可以查看服务器文件库中有什么文件
(3)客户端可以从文件库中下载文件到本地
(4)客户端可以上场一个本地文件到文件库
(5)使用print 在客户端打印命令输入提示,引导 *** 作
技术点分析:
C / S 模式
并发模型 : 多线程
网络: TCP网络
文件传输: 边读边发 边收边写
功能模块划分和封装 : 函数 + 类
搭建整体结构框架 查看文件目录 下载文件 上传文件
通信协议:
请求类型 数据参量
获取文件列表 List
下载文件 RETR filename
上传文件 STOR filename
退出 EXIT
“”"
-----------------FTP文件服务 服务端
“”"
from socket import *from threading import Threadimport os, time# 全局变量HOST = '0.0.0.0'PORT = 8888ADDR = (HOST, PORT) # 服务器地址# 文件库FTP = "/root/"# 处理客户端请求class FTPServer(Thread): def __init__(self, connfd): super().__init__() self.connfd = connfd def do_List(self): # 判断文件库是否为空 file_List = os.Listdir(FTP) if not file_List: self.connfd.send(b'FAIL') # 列表为空 return else: self.connfd.send(b'OK') time.sleep(0.1) data = "\n".join(file_List) self.connfd.send(data.encode()) # 处理下载 def do_get(self, filename): try: f = open(FTP + filename, 'rb') except: # 文件不存在报异常 self.connfd.send(b"FAIL") return else: # 文件打开成功 self.connfd.send(b"OK") time.sleep(0.1) # 发送文件 while True: data = f.read(1024) if not data: time.sleep(0.1) self.connfd.send(b"##") # 文件发送完毕 break self.connfd.send(data) f.close() # 处理上传 def do_put(self, filename): if os.path.exists(FTP + filename): self.connfd.send(b"FAIL") return else: self.connfd.send(b"OK") # 接收文件 f = open(FTP + filename, 'wb') while True: data = self.connfd.recv(1024) if data == b"##": break f.write(data) f.close() # 作为一个线程内容处理某一个客户端的请求 def run(self): # 总分模式 while True: # 某个客户端所有的请求 data = self.connfd.recv(1024).decode() print("Request:", data) # 调试 # 更具不同的请求做不同处理 if not data or data == 'EXIT': self.connfd.close() return elif data == 'List': self.do_List() elif data[:4] == 'RETR': filename = data.split(' ')[-1] self.do_get(filename) elif data[:4] == 'STOR': filename = data.split(' ')[-1] self.do_put(filename)def main(): # tcp套接字创建 sock = socket() sock.bind(ADDR) sock.Listen(5) print("Listen the port %s" % PORT) # 循环连接客户端 while True: try: connfd, addr = sock.accept() print("Connect from", addr) except KeyboardInterrupt: sock.close() return # 为连接进来的客户端创建单独的线程 t = FTPServer(connfd) # 使用自定义线程类创建线程 t.setDaemon(True) # 主线程退出,分之线程终止服务 t.start()if __name__ == '__main__': main()
---------------FTP 客户端
"""ftp文件服务客户端"""from socket import *import timeimport sys# 服务端地址ADDR = ("127.0.0.1", 8888)# 实现具体的请求功能class FTPClIEnt: def __init__(self, sock): self.sock = sock def do_List(self): self.sock.send(b"List") # 发送请求 result = self.sock.recv(128).decode() # 回复 字符串 # 根据回复分情况讨论 if result == 'OK': # 接收文件列表 file = self.sock.recv(1024 * 1024).decode() print(file) else: print("文件库为空") # 下载文件 def do_get(self, filename): data = "RETR " + filename self.sock.send(data.encode()) # 发送请求 # 等回复 result = self.sock.recv(128).decode() if result == 'OK': # 接收文件 f = open(filename, 'wb') while True: data = self.sock.recv(1024) if data == b"##": break f.write(data) f.close() else: print("文件不存在") # 上传文件 def do_put(self, filename): # 本地判断,防止文件路径写错 try: f = open(filename, 'rb') except: print("该文件不存在") return # 上传 put 后可能是路径/home/tarena/abc,提取真正的文件名 filename = filename.split('/')[-1] data = "STOR " + filename self.sock.send(data.encode()) # 发送请求 # 等回复 result = self.sock.recv(128).decode() if result == 'OK': # 发送文件 while True: data = f.read(1024) if not data: time.sleep(0.1) self.sock.send(b"##") # 文件发送完毕 break self.sock.send(data) f.close() else: print("文件已经存在") # 退出 def do_exit(self): self.sock.send(b"EXIT") self.sock.close() sys.exit("谢谢使用")def main(): # 创建套接字 sock = socket() sock.connect(ADDR) # 实例化功能类对象 ftp = FTPClIEnt(sock) while True: print("============ 命令选项==============") print("*** List ***") print("*** get file ***") print("*** put file ***") print("*** exit ***") print("==================================") cmd = input("请输入命令:") if cmd == "List": ftp.do_List() elif cmd[:3] == "get": filename = cmd.split(' ')[-1] # 提取文件名 ftp.do_get(filename) elif cmd[:3] == "put": filename = cmd.split(' ')[-1] # 提取文件名 ftp.do_put(filename) elif cmd == "exit": ftp.do_exit() else: print("请输入正确命令")if __name__ == '__main__': main()
I O 阻塞
"""非阻塞IO套接字对象 --》 非阻塞"""from socket import *import time # 打开日志文件f = open("my.log",'a') # 创建tcp套接字sockfd = socket()sockfd.bind(('0.0.0.0',8888))sockfd.Listen(5) # 设置套接字的非阻塞 # sockfd.setblocking(False) # 超时检测时间sockfd.settimeout(3)while True: print("Waiting for connect") try: connfd,addr = sockfd.accept() # 阻塞等待 print("Connect from",addr) except BlockingIOError as e: # 干点别的事 msg = "%s : %s\n"%(time.ctime(),e) f.write(msg) time.sleep(2) except timeout as e: # 干点别的事 msg = "%s : %s\n"%(time.ctime(),e) f.write(msg) else: # 正常有客户端连接 data = connfd.recv(1024) print(data.decode())
IO 多路复用
定义 : 同时监控多个IO事件,当哪个IO事件准备就绪执行哪个IO事件,以此形成可以同时处理多个IO
的行为,避免一个IO阻塞造成其他IO均无法执行,提高了IO执行效率
具体方案:
select 方法 :windows linux unix
poll 方法 : linux unix
epoll 方法: linux
select 方法 : help(select.select) #可以查看帮助文档
rs,ws,xs = select(rList,wList,xList[,timeout])
功能:监控IO事件,阻塞等待IO发生
参数: rList 列表 读IO列表 添加等待发生的或者可读的IO事件
wList 列表 写IO列表 存放要可以主动处理的或者可写的IO事件
xList 列表 异常IO列表 存放出现异常要处理的IO事件
timeout 超时时间
返回值: rs 列表 rList中准备就绪的IO ws 列表 wList中准备就绪的IO xs 列表 xList中准备就绪的IO
总结
以上是内存溢出为你收集整理的python_ftp全部内容,希望文章能够帮你解决python_ftp所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)