python ftp服务器限速_python实现ftp服务器

这个Python FTP客户端示例展示了如何连接到FTP服务器并执行基本操作,如获取、上传文件,列出目录,切换目录,创建和删除文件/目录。它还包括了密码哈希处理和错误处理。虽然没有直接实现限速,但可以作为FTP客户端实现的基础。

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

import socket

import hashlib

importstructimport os

import settingclass FtpClient(object):

features= ['get', 'put', 'ls', 'cd', 'mkdir', 'rm'] # 客户端提供的命令提供功能

def __init__(self, server_ip, port, user, pwd):''':param server_ip: 服务器ip

:param port: 服务器端口

:param user: 用户名

:param pwd: 密码''' self.server_ip =server_ip

self.port=port

self.user=user

self.pwd=pwd

self.sock=socket.socket() # 初始化时创建套接字try:

self.sock.connect((self.server_ip, self.port)) # 连接服务器

except ConnectionRefusedError:

print('501', setting.CODE['501'])returnself.pwd_hash() # 密码hashifnot self.auth():return# 验证失败

# self.run() # 登录成功继续操作

def pwd_hash(self): # 对用户输入密码进行hash

md5= hashlib.md5(setting.MD5_SALT.encode('utf-8'))

md5.update(self.pwd.encode('utf-8'))

self.pwd=md5.hexdigest()

def auth(self): # 上传用户密码进行验证

account= ','.join([self.user, self.pwd])

self.sock.send(account.encode('utf-8'))

auth_result= self.sock.recv(1024).decode() # 获取登录结果if auth_result == '8000':

print(auth_result, setting.CODE[auth_result])

self.run()else:

print(auth_result, setting.CODE[auth_result])

self.sock.close()returnFalse

def run(self):whileTrue:

user_input= input('\n>>>').strip() # 用户输入命令

command=user_input.split()

self.cmd= command[0] # 获取命令前缀if self.cmd == 'exit': # 检测到exit则退出

self.sock.close()break

else:if self.cmd inself.features: # 判断命令是否支持

self.command_s= user_input.encode('utf-8')

func=getattr(self, self.cmd) # 使用反射获取命令对应方法if len(command) == 1:if command[0] in ['get', 'put', 'cd', 'mkdir', 'rm']:

print(setting.CODE['4000'])continuefunc()

elif len(command)== 2:

func(command[1])else:

print(setting.CODE['4000'])else:

print(setting.CODE['4000'])

defget(self, *args, **kwargs):

self.send_cmd(self.command_s)

filename= args[0]

file_stat= self.sock.recv(4).decode('utf-8') # 接收文件是否找到状态码if file_stat == '1000':

tmp_file= filename + '.tmp'file_path=os.path.join(setting.DOWNLOAD_DIR, tmp_file) # 存放文件路径

real_path=os.path.join(setting.DOWNLOAD_DIR, filename)

tmp_size= 0

ifnot os.path.exists(file_path):

self.sock.sendall(b'2000')else:

self.sock.sendall(b'2001')

tmp_size=os.path.getsize(file_path)

self.sock.sendall(self.struck_info(tmp_size))

file_size= struct.unpack('i', self.sock.recv(4))[0] # 接收文件大小

receive_size= 0receive_size+=tmp_size

with open(file_path,'ab') asf:while receive_size

data= self.sock.recv(file_size -receive_size)else:

data= self.sock.recv(1024)ifnot data:

print('文件下载中断!')returnreceive_size+=len(data)

f.write(data)

self.toolbar(receive_size, file_size)

print()

src_md5= self.sock.recv(1024).decode('utf-8')

dec_md5=self.file_md5(file_path)if src_md5 ==dec_md5:

print('{}下载成功!'.format(filename))

os.rename(file_path, real_path)else:

print('文件一致性校验失败,上传失败')

os.remove(file_path)else:

print(setting.CODE[file_stat])

def put(self,*args, **kwargs):'''上传文件,断点续传

:param args:

:param kwargs:

:return:''' ifargs: # args为文件名

file_name= args[0]ifos.path.exists(file_name): # 判断文件是否存在

self.send_cmd(self.command_s)

file_size=os.path.getsize(file_name)

self.sock.send(self.struck_info(file_size)) # 发送文件大小

ques= self.sock.recv(1024).decode('utf-8') # 获取是否需要断点续传

send_size= 0# 发送的数据计数

with open(file_name,'rb') asf: # 打开文件if ques == 'all_file': # 发送整个文件

start_index= 0

else:

start_index= int(ques) # 获取断点文件大小

f.seek(start_index)

send_size+=start_indexfor line inf:

self.sock.sendall(line) # 发送数据

send_size+=len(line)

self.toolbar(send_size, file_size) # 进度条

print()

src_md5=self.file_md5(file_name) # 文件md5

self.sock.send(src_md5.encode('utf-8')) # 发送自己文件的md5

result= self.sock.recv(1024).decode('utf-8') # 获取md5比对结果,

print(result)else:

print('{} file not found!'.format(file_name))

def ls(self,*args, **kwargs):

self.send_cmd(self.cmd.encode('utf-8'))'''接收打印服务器发送的当前目录信息

:param args:

:param kwargs:

:return:''' info = self.sock.recv(4)

info_size= struct.unpack('i', info)[0] # 接收数据长度

receive_size= 0info= b''

while receive_size

data_size= 1024

if info_size - receive_size < 1024:

data_size= info_size -receive_size

data=self.sock.recv(data_size)

info+=data

receive_size+=len(data)

print(info.decode('utf-8')) # 打印目录结构

def cd(self,*args, **kwargs):'''切换目录

:param args:

:param kwargs:

:return:'''self.send_cmd(self.command_s)

print(setting.CODE[self.sock.recv(4).decode()]) # 打印切换结果

def mkdir(self,*args, **kwargs):'''创建目录

:param args:

:param kwargs:

:return:'''self.send_cmd(self.command_s)

status= self.sock.recv(1024).decode('utf-8')

print(setting.CODE[status])

def rm(self,*args, **kwargs):'''删除文件或者目录

:param args:

:param kwargs:

:return:'''self.send_cmd(self.command_s)

status= self.sock.recv(1024).decode('utf-8')

print(setting.CODE[status])

def struck_info(self, info_size):'''打包数据

:param info_size:

:return:''' return struct.pack('i', info_size)

def send_cmd(self, cmd):'''发送命令长度包和命令信息包

:param cmd:

:return:'''self.sock.send(self.struck_info(len(cmd)))

self.sock.send(cmd)

def file_md5(self, file):'''获取文件md5

:param file:

:return:''' md5 =hashlib.md5()

with open(file,'rb') asf:for i inf:

md5.update(i)returnmd5.hexdigest()

def toolbar(self, current, total):'''打印进度条

:param current:

:param total:

:return:''' val = current / total * 100print('\r{}{:.2f}%'.format(int(val) //2 * '>', val), end='')

if __name__ == '__main__':

user= input('请输入用户名:').strip()

pwd= input('请输入密码').strip()

cli= FtpClient('127.0.0.1', 8001, user, pwd)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值