分为服务端和客户端,要求可以有多个客户端同时操作。
客户端可以查看服务器文件库中有什么文件。
客户端可以从文件库中下载文件到本地。
客户端可以上传一个本地文件到文件库。
使用print在客户端打印命令输入提示,引导操作
服务端
# 导入相关模块 from socket import * from multiprocessing import Process import signal, os, time # 绑定IP地址 IP = "127.0.0.1" # 绑定端口 PORT = 8888 ADDR = (IP, PORT) # 绑定服务器的指定目录 DIR = "/home/max/ftp" # 处理查看文件请求 def browse(c): # 列表方式查看文件 list = os.listdir("%s" % DIR) # 按通信协议格式组织数据 msg = "B " + ";".join(list) # 发送到客户端 c.send(msg.encode()) # 处理客户端下载文件请求 def download(c, file): # 判断文件是否存在且是否是文件 if file in os.listdir(DIR) and os.path.isfile("%s/%s" % (DIR, file)): # 打开文件 f = open("%s/%s" % (DIR, file), "rb") # 发送下载代码,告知客户端进入"D" c.send(("D %s " % file).encode()) # 等待客户端先进入"D"模式下的recv阻塞函数 time.sleep(0.1) # 循环发送文件 while True: data = f.read(1000) if not data: # 设置间隔,等待文件传输完整 time.sleep(0.1) # 约定的信息让客户端退出接收循环 c.send(b"finished") break c.send(data) f.close() # 否则按协议格式发送错误代码 else: c.send(b"D fileerror ") # 处理客户端上传文件请求 def upload(c, file): # 创建文件 f = open("%s/%s" % (DIR, file), "wb") # 循环接收文件 while True: data = c.recv(1024) # 收到约定的信息退出循环 if data == b"finished": break f.write(data) f.close() # 处理客户端退出请求 def login_out(c): # 按协议格式组织信息 msg = "O closed " # 发给客户端的recv_msg进程 c.send(msg.encode()) def deal(c): # 发送代码告知客户端连接成功 c.send(b"K ") while True: # 循环接收客户端请求,约定通信协议为"* ** ****"格式 msg = c.recv(1024) # 如果客户端崩了,解除该子进程 if not msg: break # 解析请求 req = msg.decode().split(" ", 2) # 处理查看文件请求,跳入browse函数 if req[0] == "B": browse(c) # 处理客户端下载文件请求,跳入download函数 elif req[0] == "D": download(c, req[1]) # 处理客户端上传文件请求,跳入upload函数 elif req[0] == "U": upload(c, req[1]) # 处理客户端退出请求,跳入login_out函数 elif req[0] == "O": login_out(c) # 跳出循环,结束子进程 break # 主程序,父进程用于接收客户端请求并循环创建子进程,子程序处理请求 def main(): # 创建tcp套接字 s = socket() # 绑定服务器地址 s.bind(ADDR) # 设置监听套接字 s.listen() # 处理僵尸进程 signal.signal(signal.SIGCHLD, signal.SIG_IGN) while True: # 连接客户端 c, addr = s.accept() # 创建子进程,用以处理客户端请求,跳入deal函数 p = Process(target=deal, args=(c,)) # 子程序开始执行 p.start() if __name__ == '__main__': main()
客户端
# 导入相关模块 from socket import * import os, sys, time # 绑定服务端IP地址 IP = "127.0.0.1" # 绑定服务端端口 PORT = 8888 ADDR = (IP, PORT) # 收到约定的信息退出循环 # 发送消息进程 def send_msg(s): # 等待接收进程先运行到"K"分支 time.sleep(0.1) while True: try: # 输入指令 data = input(">") except: # 客户端错误,向服务端发送O data = "O" if data == "B": # 查看目录 msg = "B " s.send(msg.encode()) elif data == "D": # 下载文件 # 输入想要下载的文件 want = input("download ") msg = "D %s " % want s.send(msg.encode()) elif data == "U": # 上传文件 file = input("upload ") # 判断文件是否在客户端文件所在的目录且是文件 if file in os.listdir(os.getcwd()) and os.path.isfile("%s/%s" % (os.getcwd(), file)): msg = "U %s " % file s.send(msg.encode()) f = open("%s" % file, "rb") # 等待服务端进入upload的recv阻塞函数 time.sleep(0.1) while True: data = f.read(1000) if not data: # 设置间隔,等待文件传输完整 time.sleep(0.1) # 约定的信息让客户端退出接收循环 s.send(b"finished") break s.send(data) f.close() print("upload succussfully") # 否则按协议格式显示错误代码 else: print("file not exist\ninput BDUO to forward\n", end="") elif data == "O": # 断开连接 msg = "O " s.send(msg.encode()) sys.exit() # 指令错误 else: print("input error") # 接收消息进程 def recv_msg(s): while True: data = s.recv(1024) # 解析数据 msg = data.decode().split(" ", 2) if msg[0] == "K": # 登录成功反馈 print( "login in successfully\ninput B to browse,D to download,U to upload,O to login out") elif msg[0] == "B": # 查看目录反馈 # 如果文件库不为空 if msg[2]: print("files:", msg[2], "\n>", end="") else: print("files: no files", "\n>", end="") elif msg[0] == "D": # 服务端文件不存在 if msg[1] == "fileerror": print("file not exist\ninput BDUO to forward\n>", end="") continue # 服务端文件存在 else: f = open("%s" % msg[1], "wb") while True: data = s.recv(1024) # 收到约定的信息退出循环 if data == b"finished": break f.write(data) f.close() print("download successfully\n>", end="") elif msg[0] == "O": # 收到来自发送消息进程发送到服务端的断开请求 # 进程退出并打印提示 sys.exit("login out successfully") # 主程序 def main(): # 创建tcp套接字 s = socket() # 连接服务端 s.connect(ADDR) # 创建多进程,子进程用于发送消息,父进程用于接收消息 pid = os.fork() if pid < 0: print("system error") # 子进程 elif pid == 0: send_msg(s) # 父进程 else: recv_msg(s) if __name__ == '__main__': main()
总结
以上所述是小编给大家介绍的Python_模拟FTP文件服务器的操作方法,希望对大家有所帮助,也非常感谢大家对网站的支持!