Files
STM32F4-Base/test/ftp_up_dl_test.py
2026-07-21 23:05:20 +08:00

283 lines
7.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
FTP 上传+下载测试脚本
用法python ftp_up_dl_test.py --host 192.168.1.100
"""
import socket
import sys
import time
import re
import argparse
import os
HOST = "192.168.1.100"
PORT = 21
TIMEOUT = 15.0
TEST_DATA = b"Hello from Python FTP test!\r\nThis is line 2.\r\nLine 3: " + b"ABCDEFGH" * 50 + b"\r\n"
def recv_line(sock, timeout=TIMEOUT):
data = b""
sock.settimeout(timeout)
while True:
try:
ch = sock.recv(1)
except socket.timeout:
print(f" [TIMEOUT] partial: {data[:80]!r}")
return None
if not ch:
return data if data else None
data += ch
if data.endswith(b"\r\n"):
return data
def send_cmd(sock, cmd, expect_code=None):
print(f" > {cmd}")
sock.sendall((cmd + "\r\n").encode())
time.sleep(0.15)
response = recv_line(sock)
if response:
text = response.decode(errors='replace').rstrip()
print(f" < {text}")
if expect_code and not text.startswith(str(expect_code)):
print(f" *** Expected {expect_code}, got: {text}")
return None
return response
print(" < [NO RESPONSE]")
return None
def parse_pasv(resp):
m = re.search(r"(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)", resp.decode())
if m:
a, b, c, d, e, f = [int(x) for x in m.groups()]
return f"{a}.{b}.{c}.{d}", e * 256 + f
return None, None
def ftp_transfer_data(host, pasv_ip, pasv_port, cmd, data_to_send=None, read_data=False):
"""通用数据通道传输:发送命令 + 连数据端口 + 收发数据"""
print(f"\n [{cmd}] Opening data channel {pasv_ip}:{pasv_port}...")
data_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
data_sock.settimeout(10.0)
try:
data_sock.connect((pasv_ip, pasv_port))
print(f" Data channel connected.")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(TIMEOUT)
sock.connect((host, PORT))
recv_line(sock) # 220
send_cmd(sock, "USER anonymous")
send_cmd(sock, "PASS test@test.com")
# PASV
resp = send_cmd(sock, "PASV")
_, data_port = parse_pasv(resp)
print(f" PASV port: {data_port}")
# Connect data FIRST
data_sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
data_sock2.settimeout(10.0)
data_sock2.connect((pasv_ip, data_port))
# Send command
time.sleep(0.2)
send_cmd(sock, cmd)
result = None
if data_to_send:
print(f" Sending {len(data_to_send)} bytes to data channel...")
total = 0
while total < len(data_to_send):
n = data_sock2.send(data_to_send[total:])
if n <= 0:
break
total += n
print(f" Sent {total} bytes.")
data_sock2.shutdown(socket.SHUT_WR)
if read_data:
result = b""
while True:
try:
chunk = data_sock2.recv(4096)
if not chunk:
break
result += chunk
except socket.timeout:
break
print(f" Received {len(result)} bytes from data channel.")
data_sock2.close()
resp = recv_line(sock)
if resp:
print(f" Control response: {resp.decode().rstrip()}")
send_cmd(sock, "QUIT")
sock.close()
data_sock.close()
return result
except Exception as e:
print(f" Data transfer error: {e}")
try:
data_sock.close()
except:
pass
return None
def test_upload_download(host, port):
print(f"=== FTP Upload/Download Test: {host}:{port} ===\n")
# 1. Connect + Login
print("[1] Connect + Login")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(TIMEOUT)
sock.connect((host, port))
recv_line(sock) # 220
if not send_cmd(sock, "USER anonymous", 230):
sock.close(); return
if not send_cmd(sock, "PASS test@test.com", 230):
sock.close(); return
# 2. TYPE I (binary mode)
print("\n[2] Set binary mode")
send_cmd(sock, "TYPE I")
# 3. PASV + STOR (upload)
print("\n[3] Upload: STOR up_test.dat")
resp = send_cmd(sock, "PASV")
if not resp:
sock.close(); return
pasv_ip, pasv_port = parse_pasv(resp)
print(f" PASV: {pasv_ip}:{pasv_port}")
# Connect data channel
data_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
data_sock.settimeout(10.0)
try:
data_sock.connect((pasv_ip, pasv_port))
print(f" Data connected.")
except Exception as e:
print(f" Data connect FAILED: {e}")
sock.close(); return
# Send STOR
send_cmd(sock, "STOR up_test.dat")
# Send file data
total = 0
while total < len(TEST_DATA):
try:
n = data_sock.send(TEST_DATA[total:])
if n <= 0:
break
total += n
except Exception as e:
print(f" Send error: {e}")
break
print(f" Uploaded {total}/{len(TEST_DATA)} bytes.")
data_sock.shutdown(socket.SHUT_WR)
data_sock.close()
# Read STOR response
resp = recv_line(sock)
if resp:
print(f" Response: {resp.decode().rstrip()}")
# 4. PASV + LIST (verify)
print("\n[4] Verify: LIST")
resp = send_cmd(sock, "PASV")
if not resp:
sock.close(); return
pasv_ip, pasv_port = parse_pasv(resp)
data_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
data_sock.settimeout(10.0)
data_sock.connect((pasv_ip, pasv_port))
send_cmd(sock, "LIST")
data = b""
while True:
try:
chunk = data_sock.recv(4096)
if not chunk:
break
data += chunk
except socket.timeout:
break
print(f" LIST: {data.decode(errors='replace').rstrip() or '(empty directory)'}")
data_sock.close()
resp = recv_line(sock)
if resp:
print(f" Response: {resp.decode().rstrip()}")
# 5. PASV + RETR (download)
time.sleep(1.0)
print("\n[5] Download: RETR up_test.dat")
resp = send_cmd(sock, "PASV")
if not resp:
sock.close(); return
pasv_ip, pasv_port = parse_pasv(resp)
data_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
data_sock.settimeout(10.0)
try:
data_sock.connect((pasv_ip, pasv_port))
except Exception as e:
print(f" Data connect FAILED: {e}")
sock.close(); return
send_cmd(sock, "RETR up_test.dat")
dl_data = b""
while True:
try:
chunk = data_sock.recv(4096)
if not chunk:
break
dl_data += chunk
except socket.timeout:
break
data_sock.close()
resp = recv_line(sock)
if resp:
print(f" Response: {resp.decode().rstrip()}")
# Compare
print(f"\n[6] Compare")
print(f" Uploaded: {len(TEST_DATA)} bytes")
print(f" Downloaded: {len(dl_data)} bytes")
if dl_data == TEST_DATA:
print(f" *** MATCH! Upload/Download success. ***")
else:
print(f" *** MISMATCH! ***")
if dl_data:
print(f" First 80 bytes uploaded: {TEST_DATA[:80]!r}")
print(f" First 80 bytes downloaded: {dl_data[:80]!r}")
# 7. DELE (delete test file)
print("\n[7] Cleanup: DELE up_test.dat")
send_cmd(sock, "DELE up_test.dat")
# 8. QUIT
print("\n[8] QUIT")
send_cmd(sock, "QUIT")
sock.close()
print("\n=== Test Complete ===")
def main():
parser = argparse.ArgumentParser(description="FTP Upload/Download Test")
parser.add_argument("--host", default=HOST)
parser.add_argument("--port", type=int, default=PORT)
args = parser.parse_args()
test_upload_download(args.host, args.port)
if __name__ == "__main__":
main()