ftp文件服务器搭建

本文介绍了一个基于Python的简单FTP服务器的设计与实现过程,包括服务端与客户端的交互流程、功能模块划分及关键技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 项目功能:
 * 服务端和客户端两个部分,要求启动一个服务端,可以同时处理多个客户端请求
 * 功能: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服务端具体代码
'''
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客户端具体代码
'''
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()	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值