需求原因
机器需要上传文件到服务器,sftp经常失败,改为http上传测试
python代码
vim uploadfile.py
其中 /tmp改为你要写入的根目录
USERNAME PASSWORD参数值改为复杂一点的账号密码
import http.server
import socketserver
import os
import threading
import base64
import pwd
import grp
PORT = 8107 # 选择一个空闲端口
DIRECTORY = "/tmp" # 文件存储根目录
USERNAME = "user" # 设置用户名
PASSWORD = "password" # 设置密码
OWNER = "datauser1" # 设置文件所有者
GROUP = "datagroup1" # 设置文件用户组
# 自定义请求处理类
class SimpleHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
def do_POST(self):
self.handle_upload()
def do_PUT(self):
self.handle_upload()
def handle_upload(self):
# 验证用户名和密码
if not self.authenticate():
self.send_response(401)
self.send_header('WWW-Authenticate', 'Basic realm="File Upload"')
self.end_headers()
return
# 解析请求,获取文件信息
length = int(self.headers['Content-Length'])
filename = os.path.basename(self.path)
directory = os.path.dirname(self.path)
path = os.path.join(DIRECTORY, directory[1:], filename)
# 逐级创建多级目录并设置权限
current_dir = DIRECTORY
for dir_name in directory.split('/'):
if dir_name:
current_dir = os.path.join(current_dir, dir_name)
os.makedirs(current_dir, exist_ok=True)
os.chown(current_dir, pwd.getpwnam(OWNER).pw_uid, grp.getgrnam(GROUP).gr_gid)
# 写入文件
with open(path, 'wb') as f:
f.write(self.rfile.read(length))
# 获取所有者对应的UID和用户组对应的GID
uid = pwd.getpwnam(OWNER).pw_uid
gid = grp.getgrnam(GROUP).gr_gid
# 更改文件所有者和用户组
os.chown(path, uid, gid) # 设置所有者为OWNER对应的UID,用户组为GROUP对应的GID
self.send_response(200)
self.end_headers()
def authenticate(self):
# 获取Authorization头部的值
auth_header = self.headers.get('Authorization')
if auth_header:
# 解码用户名和密码
auth_bytes = base64.b64decode(auth_header.split(' ')[1])
auth_str = auth_bytes.decode('utf-8')
# 检查用户名和密码是否匹配
username, password = auth_str.split(':')
return username == USERNAME and password == PASSWORD
return False
# 创建HTTP服务器,使用ThreadingMixIn实现并发处理
class ThreadedHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
pass
# 创建并启动HTTP服务器
with ThreadedHTTPServer(("", PORT), SimpleHTTPRequestHandler) as httpd:
print("服务器已启动,端口号:", PORT)
# 持续运行服务器
httpd.serve_forever()
启动
当前终端运行
python3 uploadfile.py
后台运行
nohup python3 uploadfile.py >dev/null 2>&1 &
开机运行
要将Python脚本添加为CentOS 7的开机启动项,您可以创建一个Systemd服务单元文件。下面是一个简单的步骤:
- 创建一个新的Systemd服务单元文件。打开终端并键入以下命令:
sudo vim /etc/systemd/system/uploadfile.service
- 在编辑器中,添加以下内容:
[Unit]
Description=Upload File Service
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /root/scropts/uploadfile.py
Restart=on-failure
[Install]
WantedBy=multi-user.target
确保将 ExecStart
的路径指向您的Python解释器和脚本位置。
-
保存并关闭文件。
-
使用以下命令重新加载Systemd管理的服务单元列表,以使新添加的服务生效:
sudo systemctl daemon-reload
- 现在您可以启动、停止、重启和查看服务状态了:
- 启动服务:
sudo systemctl start uploadfile
- 停止服务:
sudo systemctl stop uploadfile
- 重启服务:
sudo systemctl restart uploadfile
- 查看服务状态:
sudo systemctl status uploadfile
- 如果您希望脚本在系统启动时自动启动,可以使用以下命令:
sudo systemctl enable uploadfile
现在,您的Python脚本将在系统启动时自动运行。
测试命令
支持PUT 或 POST 提交文件
curl -X PUT --user user:password --data-binary "@D:\WorkFile\x.txt" http://192.168.0.11:8000/mps/H30/y.txt
curl -X POST --user user:password --data-binary "@D:\WorkFile\x.txt" http://192.168.0.11:8000/mps/H30/y.txt
这个命令实现是将本地D:\WorkFile\x.txt上传到写入服务器的 /tmp/mps/H30/y.txt ,如果目录/tmp/mps/H30/不存在将自动创建
English version
Building an HTTP File Upload Server with Python 3
Reason for Requirement
The machine needs to upload files to the server. Since SFTP often fails, HTTP upload is tested as an alternative.
Python Code
Open a terminal and type the following command:
vim uploadfile.py
In the editor, add the following content. Replace /tmp
with the root directory where you want to write, and change the USERNAME
and PASSWORD
parameter values to complex account passwords.
import http.server
import socketserver
import os
import threading
import base64
import pwd
import grp
PORT = 8107 # Select an available port
DIRECTORY = "/tmp" # Root directory for file storage
USERNAME = "user" # Set the username
PASSWORD = "password" # Set the password
OWNER = "datauser1" # Set the file owner
GROUP = "datagroup1" # Set the file group
# Custom request handler class
class SimpleHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
def do_POST(self):
self.handle_upload()
def do_PUT(self):
self.handle_upload()
def handle_upload(self):
# Authenticate username and password
if not self.authenticate():
self.send_response(401)
self.send_header('WWW-Authenticate', 'Basic realm="File Upload"')
self.end_headers()
return
# Parse the request and get file information
length = int(self.headers['Content-Length'])
filename = os.path.basename(self.path)
directory = os.path.dirname(self.path)
path = os.path.join(DIRECTORY, directory[1:], filename)
# Create multiple directories and set permissions
current_dir = DIRECTORY
for dir_name in directory.split('/'):
if dir_name:
current_dir = os.path.join(current_dir, dir_name)
os.makedirs(current_dir, exist_ok=True)
os.chown(current_dir, pwd.getpwnam(OWNER).pw_uid, grp.getgrnam(GROUP).gr_gid)
# Write the file
with open(path, 'wb') as f:
f.write(self.rfile.read(length))
# Get UID and GID corresponding to owner and group
uid = pwd.getpwnam(OWNER).pw_uid
gid = grp.getgrnam(GROUP).gr_gid
# Change file owner and group
os.chown(path, uid, gid) # Set owner to UID of OWNER, group to GID of GROUP
self.send_response(200)
self.end_headers()
def authenticate(self):
# Get value of Authorization header
auth_header = self.headers.get('Authorization')
if auth_header:
# Decode username and password
auth_bytes = base64.b64decode(auth_header.split(' ')[1])
auth_str = auth_bytes.decode('utf-8')
# Check if username and password match
username, password = auth_str.split(':')
return username == USERNAME and password == PASSWORD
return False
# Create HTTP server with ThreadingMixIn for concurrent handling
class ThreadedHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
pass
# Create and start HTTP server
with ThreadedHTTPServer(("", PORT), SimpleHTTPRequestHandler) as httpd:
print("Server started on port:", PORT)
# Keep the server running
httpd.serve_forever()
Start
Run in the current terminal
python3 uploadfile.py
Run in the background
nohup python3 uploadfile.py >/dev/null 2>&1 &
Run at startup
To add the Python script as a startup item in CentOS 7, you can create a Systemd service unit file. Here are the steps:
- Create a new Systemd service unit file. Open a terminal and type the following command:
sudo vim /etc/systemd/system/uploadfile.service
- In the editor, add the following content:
[Unit]
Description=Upload File Service
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /root/scropts/uploadfile.py
Restart=on-failure
[Install]
WantedBy=multi-user.target
Make sure to replace the path in ExecStart
with the location of your Python interpreter and script.
-
Save and close the file.
-
Use the following command to reload the list of Systemd-managed service units to apply the changes:
sudo systemctl daemon-reload
- Now you can start, stop, restart, and view the status of the service:
- Start the service:
sudo systemctl start uploadfile
- Stop the service:
sudo systemctl stop uploadfile
- Restart the service:
sudo systemctl restart uploadfile
- View the service status:
sudo systemctl status uploadfile
- If you want the script to start automatically when the system boots, you can use the following command:
sudo systemctl enable uploadfile
Now, your Python script will run automatically when the system starts.
Test Command
PUT OR POST
curl -X PUT --user user:password --data-binary "@D:\WorkFile\x.txt" http://192.168.0.11:8000/mps/H30/y.txt
curl -X POST --user user:password --data-binary "@D:\WorkFile\x.txt" http://192.168.0.11:8000/mps/H30/y.txt
This command uploads the local file D:\WorkFile\x.txt
to /tmp/mps/H30/y.txt
on the server. If the directory /tmp/mps/H30/
does not exist, it will be created automatically.
近期评论