使用Paramiko SFTP上传时触发FileNotFoundError问题排查
问题:SFTP上传时出现FileNotFoundError
运行Flask上传代码时,执行sftp.putfo操作时报错FileNotFoundError: [Errno 2] No such file,怀疑与SSH配置Subsystem sftp internal-sftp有关,需排查解决。
相关代码
@app.route('/success', methods=['POST']) def success(): try: now = datetime.now() dt_string = now.strftime("%d/%m/%Y %H:%M:%S") print("You are uploading at", dt_string) hostname = socket.gethostname() client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((ip, 9090)) # Connect to server UUID = str(uuid.uuid4()) header_data = "{ \n" + socket.gethostbyname(hostname) + "\n SCOPE:upload \n" + dt_string + "\n" + UUID + "\n}" with open("header.txt", "w") as datasave: datasave.write(header_data) client_socket.send(header_data.encode()) data_from_server = client_socket.recv(1024).decode() with open("header_response.txt", "w") as datasave: datasave.write(data_from_server) print(data_from_server) with open("header_response.txt", "r") as header_file: header = header_file.read() usr = header.split("USR: ")[1].split("\n")[0].strip() passwd = header.split("PASSWD: ")[1].split("\n")[0].strip() os.system("sudo rm header_response.txt") os.system("sudo rm header.txt") ssh = paramiko.SSHClient() ssh.load_system_host_keys() ssh.connect(ip, username=usr, password=passwd) print('a trecut') sftp = ssh.open_sftp() with open("data.nimb", 'w') as d: d.write(UUID + '\n' + dt_string + "\n") with open('data.nimb', 'rb') as miau: with paramiko.SSHClient() as ssh: sftp.putfo(miau, '/incoming/' + "data.nimb") os.remove('data.nimb') code = str(random.randint(1000000000, 9999999999)) con = sqlite3.connect(db_file) cursor = con.cursor() cursor.execute("INSERT INTO users (username, password, code, uuid) VALUES (?, ?, ?, ?)", (usr, passwd, code, UUID)) con.commit() uploaded_filenames = [] # Initialize a list to store uploaded filenames for uploaded_file in request.files.getlist('file'): filename = uploaded_file.filename uploaded_filenames.append(filename) # Save the filename to the list sftp.putfo(uploaded_file, '/incoming/' + filename) sftp.close() ssh.close() #print(uploaded_filenames) # Send the uploaded filenames to the specified IP address #send_filenames(uploaded_filename) return render_template('success.html', code=code, filenames=uploaded_filenames) except Exception as e: traceback.print_exc() # Print traceback information including line number app.logger.error('An error occurred: {}'.format(str(e))) # Handle the error and return an appropriate response return render_template('error.html', message="An error occurred")
报错信息
Traceback (most recent call last): File "/home/nimbus-pi/mlrasp/web/app.py", line 81, in success sftp.putfo(miau, '/incoming/' + "data.nimb") File "/root/.pyenv/versions/3.9.16/lib/python3.9/site-packages/paramiko/sftp_client.py", line 714, in putfo with self.file(remotepath, "wb") as fr: File "/root/.pyenv/versions/3.9.16/lib/python3.9/site-packages/paramiko/sftp_client.py", line 372, in open t, msg = self._request(CMD_OPEN, filename, imode, attrblock) File "/root/.pyenv/versions/3.9.16/lib/python3.9/site-packages/paramiko/sftp_client.py", line 822, in _request return self._read_response(num) File "/root/.pyenv/versions/3.9.16/lib/python3.9/site-packages/paramiko/sftp_client.py", line 874, in _read_response self._convert_status(msg) File "/root/.pyenv/versions/3.9.16/lib/python3.9/site-packages/paramiko/sftp_client.py", line 903, in _convert_status raise IOError(errno.ENOENT, text) FileNotFoundError: [Errno 2] No such file [2023-07-15 19:57:54,939] ERROR in app: An error occurred: [Errno 2] No such file
排查与解决方案
1. 修复代码逻辑错误
上传data.nimb时多余嵌套的paramiko.SSHClient()上下文会覆盖原有ssh变量,导致SFTP连接异常,修改该段代码:
原错误代码:
with open('data.nimb', 'rb') as miau: with paramiko.SSHClient() as ssh: sftp.putfo(miau, '/incoming/' + "data.nimb")
修改为:
with open('data.nimb', 'rb') as miau: sftp.putfo(miau, '/incoming/data.nimb')
2. 确认远程目录存在且权限合规
- 登录远程服务器,检查
/incoming目录是否存在:
不存在则创建:ls -ld /incomingmkdir -p /incoming - 确保登录用户
usr拥有该目录读写权限:chown usr:usr /incoming # 替换为实际用户及用户组 chmod 755 /incoming
3. 检查SSH的internal-sftp配置
若使用Subsystem sftp internal-sftp并配置ChrootDirectory,需注意:
ChrootDirectory指定的路径必须由root用户拥有,权限为755(不可设为777)/incoming需位于ChrootDirectory内部,例如ChrootDirectory /home/chroot时,实际物理路径为/home/chroot/incoming,需确保该路径存在且权限正确- 确认SSH配置文件(通常为
/etc/ssh/sshd_config)的相关配置:
修改后重启SSH服务:Subsystem sftp internal-sftp Match User usr ChrootDirectory /home/chroot ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding nosudo systemctl restart sshd
4. 代码优化(可选)
使用上下文管理器自动管理SSH和SFTP连接,避免手动关闭导致的资源泄漏:
# 替换原有的ssh和sftp初始化代码 with paramiko.SSHClient() as ssh: ssh.load_system_host_keys() ssh.connect(ip, username=usr, password=passwd) with ssh.open_sftp() as sftp: # 所有SFTP操作都在此块内执行 with open("data.nimb", 'w') as d: d.write(UUID + '\n' + dt_string + "\n") with open('data.nimb', 'rb') as miau: sftp.putfo(miau, '/incoming/data.nimb') os.remove('data.nimb') # 处理文件上传循环 uploaded_filenames = [] for uploaded_file in request.files.getlist('file'): filename = uploaded_file.filename uploaded_filenames.append(filename) sftp.putfo(uploaded_file, f'/incoming/{filename}')
内容的提问来源于stack exchange,提问作者VladAndrei
相关产品推荐
相关产品推荐

