ftp文件服务器
一、项目功能
1.服务端和客户端两部分,要求启动一个服务端可以同时处理多个客户端请求
2.功能:1).可以查看服务端文件库中所有的普通文件
2).从客户端可以下载文件库的文件到本地
3).可以将本地文件上传到服务端文件库
4).退出
3. 客户端使用print在终端打印简单的命令提示,通过命令提示发起请求
二、技术分析
1.技术分析-(fork,tcp并发)
2.每个功能要单独封装,整体功能写在一个类中
3.如何搭建整体架构,完成网络通讯
三、功能分析
获取文件列表
客户端: *发送请求
*得到回复判断能否获取列表
*接收文件名称列表打印
服务端: * 接收请求
* 判断请求类型
* 判断能否满足请求,回复信息确认
* 执行请求发送文件列表
-------------------------------------------------------------------------------------华丽分割线 ~_~
- 服务端程序
'''
ftp 文件服务器
'''
from socket import *
import time
import os,sys
import signal
#文件库路径
file_path = '/home/file/ftp/'
HOST = ''
PORT = 5000
ADDR = (HOST,PORT)
#将文件服务器功能写在类中
class FtpServer(object):
def __init__(self,c):
self.c = c
def do_list(self):
#获取文件列表
file_list = os.listdir(file_path)
if not file_list:
self.c.send('文件库为空'.encode())
return
else:
self.c.send(b'OK')
time.sleep(0.1)
files = ''
for file in file_list:
if file[0] != '.' and os.path.isfile(file_path+file):
files = files + file + '#'
self.c.sendall(files.encode())
def do_get(self,filename):
try:
fd = open(file_path + filename,'rb')
except:
self.c.send('文件不存在'.encode())
return
self.c.send(b'OK')
time.sleep(0.1)
#发送文件
while True:
data = fd.read(1024)
if not data:
time.sleep(0.1)
self.c.send(b'##')
break
self.c.send(data)
print('文件发送完毕')
fd.close()
def do_upload(self,filename):
try:
fd = open(file_path+filename,'wb')
except:
self.c.send('文件上传失败'.encode())
return
self.c.send(b'OK')
while True:
data = self.c.recv(1024)
if data == b'##':
break
fd.write(data)
fd.close()
print('%s上传完毕'%filename)
#创建套接字,接收客户端连接,创建新的流程
def main():
sockfd = socket()
sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
sockfd.bind(ADDR)
sockfd.listen(5)
#处理子进程退出
signal.signal(signal.SIGCHLD,signal.SIG_IGN)
print('listen the port 5000...')
while True:
try:
c,addr = sockfd.accept()
except KeyboardInterrupt:
sockfd.close()
sys.exit('服务器退出')
except Exception as e:
print('服务器异常:',e)
continue
print('已连接客户端:',addr)
#创建子进程
pid = os.fork()
#子进程处理具体请求
if pid == 0:
sockfd.close()
ftp=FtpServer(c)
#判断客户请求
while True:
data=c.recv(1024).decode()
if not data:
c.close()
sys.exit('客户端退出')
elif data[0]=='L':
ftp.do_list()
elif data[0]=='G':
filename=data.split(' ')[-1]
ftp.do_get(filename)
elif data[0]=='U':
filename=data.split(' ')[-1]
ftp.do_upload(filename)
#父进程或者创建失败,都继续等待下个客户端连接
else:
c.close()
continue
if __name__ == '__main__':
main()
- 客户端程序
-
from socket import * from menu import show_menu import sys import time #基本文件操作功能写在类里 class FtpClient(object): def __init__(self,sockfd): self.sockfd=sockfd def do_list(self): self.sockfd.send(b'L')#发送请求 #等待回复 data = self.sockfd.recv(1024).decode() if data == 'OK': data = self.sockfd.recv(4096).decode() files = data.split('#') for file in files: print(file) print('文件列表展示完毕\n') else: #由服务器发送请求失败原因 print(data) def do_get(self,filename): self.sockfd.send(('G '+filename).encode()) data = self.sockfd.recv(1024).decode() if data == 'OK': fd = open(filename,'wb') while True: data=self.sockfd.recv(1024) if data==b'##': break fd.write(data) fd.close() print('%s下载完毕\n'%filename) else: print(data) def do_upload(self,filename): try: fd=open(filename,'rb') except: print('文件打开失败') return self.sockfd.send(('U '+filename).encode()) data=self.sockfd.recv(1024).decode() if data=='OK': while True: data=fd.read(1024) if not data: time.sleep(0.1) self.sockfd.send(b'##') break self.sockfd.send(data) fd.close() print('%s上传完毕'%filename) else: print(data) #网络连接 def main(): if len(sys.argv) < 3: print('argv is error') return HOST = sys.argv[1] PORT = int(sys.argv[2]) ADDR = (HOST,PORT)#文件服务器地址/服务端地址 #创建套接字,跟服务端相同 sockfd=socket() try: sockfd.connect(ADDR) except: print('连接服务器失败') return ftp = FtpClient(sockfd) #功能类对象 while True: show_menu() cmd = input('请输入命令>>:') if not cmd: break elif cmd.strip()== '1' : ftp.do_list() elif cmd.strip()[0] =='2': filename=cmd.split(' ')[-1] ftp.do_get(filename) elif cmd.strip()[0]=='3': filename=cmd.split(' ')[-1] ftp.do_upload(filename) elif cmd.strip()[0]=='4': sys.exit(0) else: print('请输入正确命令!!!') continue # #关闭套接字 # sockfd.close() if __name__ == '__main__': main()