* 服务端和客户端两个部分,要求启动一个服务端,可以同时处理多个客户端请求
* 功能:1. 可以查看服务端文件库中所有的普通文件
2.从客户端可以下载文件库的文件到本地
3.可以将本地文件上传到服务端文件库
4.退出
* 客户端使用print在终端打印简单的命令提示,通过命令提示发起请求
* 技术分析(fork tcp 并发)
* 每个功能要单独封装,整体功能写在一个类中
* 如何搭建整体架构,完成网络通讯
'''
ftp服务器端
'''
import os,sys,signal
import time
from socket import *
ftpFile = '~/ftpFile/'
Host = '0.0.0.0'
Port = 8888
Addr = (Host,Port)
def FtpServer(object):
pass
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 to the port 8888')
#等待连接客户端
while True:
try:
connfd,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()
print('执行客户端请求')
sys.exit()
else:
connfd.close()
continue
if __name__ == '__main__':
main()
'''
ftp客户端
'''
from socket import *
import sys,os,time
def order():
print('----------命令选项---------')
print('*********list*********')
print('*********get file*********')
print('*********put file*********')
print('*********quit*********')
print('----------------------')
#基本文件操作
class FtpServer(object):
pass
#网络连接
def main():
addr_str = input('输入服务器端地址:')
Host,Port = addr_str.split()
Addr = Host,int(Port)
sockfd = socket()
try:
sockfd.connect(Addr)
except:
prtin('连接服务器失败')
return
order()
if __name__ == '__main__':
main()
1.获取文件列表
客户端: * 发送请求
* 得到回复判断能否获取列表
* 接收文件名称列表(注意粘包)
服务端: * 接收请求
* 判断请求类型
* 判断能否满足请求,回复消息确认
* 执行请求发送文件列表
* Cookie:
os.listdir(path) 可以查看path路径下的所有文件内容
os.path.isdir(path) 可以查看path是否是文件夹
os.path.isfile(path) 可以查看path是否是普通文件
2.从服务端下载文件到本地
客户端:
1.发送请求 (文件名)
2.得到回复判断是否能够获取该文件
3.判断该文件格式
4.接收文件内容
5.根据标识确认文件接收完毕
服务端:
1.接收请求
2.接收文件名并判断是否存在该文件
3.判断文件是否可下载
4.发送文件内容,发送完后设置间隔发送完成标识,避免粘包
5.打印谁下载什么文件
3.从客户端上传文件到文件库
客户端:
1.发送请求(文件名)
2.根据文件是否在文件库中判断是否可以上传
3.上传文件到服务端
服务端:
1.接收请求
2.判断文件是否已存在与文件库
3.判断文件是否可上传
4.接收文件内容
5.打印谁上传了什么内容
4.退出
客户端:
1.发送退出请求
2.关闭套接字、杀死进程
3.屏幕打印‘谢谢使用’
服务端:
1.接收退出请求
2.关闭套接字、杀死进程
3.屏幕打印谁退出了服务端
'''
ftp服务器端
'''
import os,sys,signal
import time
from socket import *
FilePath = '/home/king/ftpFile/'
file_list = os.listdir(FilePath)
Host = '0.0.0.0'
Port = 8888
Addr = (Host,Port)
#将文件服务器功能写在类中
class FtpServer(object):
def __init__(self,connfd):
self.connfd = connfd
self.file_list = file_list
def do_list(self):
#获取文件列表
file_list = os.listdir(FilePath)
if not file_list:
self.connfd.send('文件库为空'.encode())
return
else:
self.connfd.send(b'OK')
time.sleep(0.2)
files = ''
for file in file_list:
if file[0] != '.' and os.path.isfile(FilePath+file):
files = files + file + '#'
self.connfd.sendall(files.encode())
def do_download(self,filename):
#执行下载操作
try:
fr = open(FilePath+filename,'rb')
except:
self.connfd.send('文件不存在或打开失败'.encode())
return False
self.connfd.send(b'filename correct')
time.sleep(0.2)
#发送文件
while True:
file_content = fr.read(1024)
if not file_content:
time.sleep(0.2) # 避免粘包
self.connfd.send(b'##')
break
self.connfd.send(file_content)
fr.close()
return True
def do_upload(self,filename):
#执行上传操作
if filename in self.file_list:
self.connfd.send('文件已存在与列表中'.encode())
return False
else:
self.connfd.send('OK'.encode())
fr = open(FilePath + filename,'wb')
while True:
data = self.connfd.recv(1024)
if data == b'##':
fr.close()
break
fr.write(data)
return True
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 to the port 8888')
#等待连接客户端
while True:
try:
connfd,addr = sockfd.accept()
except KeyboardInterrupt:
sockfd.close()
sys.exit('服务器退出')
except Exception as e:
print('服务器异常',e)
continue
print('已连接客户端:',addr)
#创建子进程
pid = os.fork()
if pid == 0:
ftp = FtpServer(connfd)
sockfd.close()
#print('执行客户端请求')
while True:
data = connfd.recv(1024).decode()
if not data or data[0] == 'Q':
connfd.close()
sys.exit('客户端退出:{}'.format(addr))
elif data[0] == 'L':
ftp.do_list()
print('向{}展示了文件库列表'.format(addr))
elif data[0] == 'D':
filename = data.split(' ')[-1]
flag = ftp.do_download(filename)
if flag:
print('{}文件下载成功:{}'.format(filename,addr))
elif data[0] == 'U':
filename = data.split(' ')[-1]
flag = ftp.do_upload(filename)
if flag:
print('{}文件上传成功:{}'.format(filename,addr))
else:
connfd.close()
continue
if __name__ == '__main__':
main()
'''
ftp客户端
'''
from socket import *
import sys,os,time
def order():
print('----------命令选项---------')
print('*********list*********')
print('*********get file*********')
print('*********put file*********')
print('*********quit*********')
print('----------------------')
#基本文件操作
class FtpClient(object):
def __init__(self,sockfd):
self.sockfd = sockfd
self.files = ''
def do_list(self):
#查看文件库列表
self.sockfd.send(b'L ')
data = self.sockfd.recv(1024).decode()
if data == 'OK':
data = self.sockfd.recv(4096).decode()
self.files = data.split('#')
for i,file in enumerate(self.files):
print(i,file)
print('文件列表展示完毕\n')
else:
#由服务器发送失败的原因
print(data)
def do_download(self,filename):
#执行下载操作
self.sockfd.send(('D '+filename).encode())
data = self.sockfd.recv(1024).decode()
if data == 'filename correct':
fw = open(filename,'wb')
while True:
file_content = self.sockfd.recv(1024)
if file_content == b'##':
break
fw.write(file_content)
print('{}下载成功'.format(filename))
fw.close()
else:
print(data)
def do_upload(self,filename):
#执行上传操作
try:
fr = open(filename,'rb')
except Exception as e:
print('打开文件失败:',e)
return
self.sockfd.send(('U ' + filename).encode())
data = self.sockfd.recv(1024).decode()
if data == 'OK':
while True:
file_content = fr.read(1024)
if not file_content:
time.sleep(0.2)
self.sockfd.send(b'##')
break
self.sockfd.send(file_content)
print('{}上传成功'.format(filename))
else:
print(data)
def do_localList():
pass
def do_quit(self):
self.sockfd.send(b'Q')
#网络连接
def main():
addr_str = input('输入服务器端地址:')
Host,Port = addr_str.split()
Addr = Host,int(Port)
sockfd = socket()
try:
sockfd.connect(Addr)
except:
prtin('连接服务器失败')
return
ftp = FtpClient(sockfd) # 功能类对象,发现每个功能都需要sockfd参数
while True:
order()
cmd = input('请输入命令>>')
if cmd.strip() == 'list':
ftp.do_list()
elif cmd[:3] == 'get':
filename = cmd.split(' ')[-1]
ftp.do_download(filename)
elif cmd.strip() == 'quit':
ftp.do_quit()
sockfd.close()
sys.exit('谢谢使用')
elif cmd[:3] == 'put':
filename = cmd.split(' ')[-1]
ftp.do_upload(filename)
else:
print('请输入正确的命令!')
if __name__ == '__main__':
main()