文档分析
需求 :
* 分为服务端和客户端,要求可以有多个客户端同时操作。
* 客户端可以查看服务器文件库中有什么文件。
* 客户端可以从文件库中下载文件到本地。
* 客户端可以上传一个本地文件到文件库。
* 使用print在客户端打印命令输入提示,引导操作
1. 文件库可能为空,此时看不了文件库
2. 要下载的文件不存在
3. 上传时文件库有同名的文件
技术点 :
网络: tcp
并发模型 : 多进程 多线程 并发
功能划分和封装: 封装
框架搭建 : 函数
查看文件库内容
下载文件
上传文件
退出
协议设计 :
请求类型 数据参量
查看 LOOK
上传 UP 文件名/带路径的文件
下载 DOWN 文件名
退出 EXIT
服务端反馈约定 : OK
NO
具体功能模块设计:
框架搭建 服务端 :
客户端 :
查看文件库内容
客户端 : 1. 发起请求
2. 等待服务端反馈结果
3. Yes -> 接收文件列表
No -> 结束
服务端 : 1. 接收请求
2. 判断请求是否可以完成
将反馈结果发送给客户端
3. Yes 发送文件列表
No 结束
上传文件
客户端 : 发送请求
等待反馈
Yes 上传文件
No 结束
服务端 : 接收请求
判断文件是否已存在
发送反馈
Yes 接收文件
No 结束
下载文件
客户端 : 发送请求
发送数据参量 文件名
等待反馈结果
服务端 : 接收请求
判断文件是否存在 存在/不存在(文件名有误)
发送反馈结果
退出
客户端:
考虑异常退出的情况
服务端:
考虑客户端异常退出的情况
注:后续还需优化处理,写的不是很好,只供参考
服务端代码
# -*- coding: UTF-8 -*-
'''
PyCharm
@Project :文件传输
@File :ftp_server.py
@Author :
@Date :2020/10/24
'''
"""
服务端
"""
from socket import *
from multiprocessing import Process
from signal import *
import os, time
# 文件库位置
ilbrary = '/home/桌面/学习/'
# 下载位置
local_ilbrary = '/home/桌面/下载1/'
file = os.listdir(ilbrary)
# print(files)
POST = '0.0.0.0'
PORT = 8888
ADDR = (POST, PORT)
# 处理查看文件列表
def files(connfd):
str_file = ''
if file == []:
connfd.send('无文件'.encode())
for filename in file:
str_file += filename + '\n'
connfd.send(str_file.encode())
time.sleep(0.1)
connfd.send(b'##')
# 处理上传
def upload_file(connfd, fileaddr):
filename = fileaddr.split('/')[-1]
if os.path.exists(ilbrary + filename):
connfd.send('上传文件已存在'.encode())
return
connfd.send('OK'.encode())
up_file = open(ilbrary + filename, 'wb')
while True:
data = connfd.recv(1024)
if data == b'##':
break
up_file.write(data)
up_file.close()
# 处理下载
def download_file(connfd, filename):
if os.path.exists(ilbrary + filename):
file = open(ilbrary + filename, 'rb')
if os.path.exists(local_ilbrary + filename):
connfd.send('下载的文件重复'.encode())
return
else:
down_file = open(local_ilbrary + filename, 'wb')
while True:
data = file.read(1024)
down_file.write(data)
if not data:
break
connfd.send('下载成功'.encode())
file.close()
down_file.close()
else:
connfd.send('文件不存在'.encode())
return
# 处理退出
def exits(connfd):
connfd.send('拜拜'.encode())
# 处理请求
def request(connfd):
while True:
try:
data = connfd.recv(1024)
tmp = data.decode().split(' ', 1)
print(tmp)
except KeyboardInterrupt:
return
if not data:
break
if tmp[0] == 'LOOK':
files(connfd)
elif tmp[0] == 'UP':
upload_file(connfd, tmp[1])
elif tmp[0] == 'DOWN':
download_file(connfd, tmp[1])
elif tmp[0] == 'EXIT':
exits(connfd)
connfd.close()
# 启动函数
def main():
socketed = socket()
socketed.bind(ADDR)
socketed.listen(5)
signal(SIGCHLD,SIG_IGN)
while True:
try:
connfd, addr = socketed.accept()
except KeyboardInterrupt:
socketed.close()
return
process = Process(target=request, args=(connfd,))
Process.daemon=True
process.start()
if __name__ == '__main__':
main()
客户端代码
# -*- coding: UTF-8 -*-
'''
PyCharm
@Project :文件传输
@File :ftp_client.py
@Author :
@Date :2020/10/24
'''
"""
客户端
"""
from socket import *
import sys, time
#服务器地址
ADDR = ('127.0.0.1', 8888)
# 文件列表
def file_list(socketed, msg):
socketed.send(msg.encode())
while True:
data = socketed.recv(1024)
print('文件列表:')
if data == b'##':
return
print(data.decode())
# 下载文件
def down_file(socketed):
filename = input('要下载的文件名:')
afreement = 'DOWN %s' % filename
socketed.send(afreement.encode())
data = socketed.recv(1024)
if not data:
return
print(data.decode())
# 上传文件
def up_file(socketed):
fileaddr = input('要上传的文件地址:')
try:
file = open(fileaddr, 'rb')
except FileNotFoundError:
print('文件不存在')
return
afreement = f'UP {fileaddr}'
socketed.send(afreement.encode())
data = socketed.recv(1024)
if data == b"OK":
while True:
message = file.read(1024)
if not message:
break
socketed.send(message)
print('文件上传成功')
file.close()
time.sleep(0.1)
socketed.send(b'##')
else:
print(data.decode())
# 退出
def sign_out(socketed, msg):
socketed.send(msg.encode())
data = socketed.recv(1024)
if data.decode() == '拜拜':
sys.exit('谢谢使用')
def main():
socketed = socket()
socketed.connect(ADDR)
while True:
print('--------功能选项--------')
print('LOOK---UP---DOWN---EXIT')
try:
msg = input('请输入:')
if not msg:
break
except KeyboardInterrupt:
socketed.close()
break
if msg == 'LOOK':
file_list(socketed, msg)
elif msg == 'UP':
up_file(socketed)
elif msg == 'DOWN':
down_file(socketed)
elif msg == 'EXIT':
sign_out(socketed, msg)
else:
print('请输入有效指令!')
if __name__ == '__main__':
main()