🔹 阶段 1:生成"权威文件清单"(manifest)
这是"文件完整性的法律文件",后面一切都以它为准
✅ 在【源服务器】执行(非常快、只读)
cd /opt/jyd01/wangruihua/api_docker/jyd_digital
python3 - << 'EOF'
import os, json
BASE = "jyd_heygem"
files = []
for root, dirs, filenames in os.walk(BASE):
for name in filenames:
full = os.path.join(root, name)
try:
size = os.path.getsize(full)
except:
continue
rel = os.path.relpath(full, BASE)
files.append({"path": rel, "size": size})
print("TOTAL files:", len(files))
with open("jyd_heygem_manifest.json", "w") as f:
json.dump(files, f)
EOF
你会看到类似:
TOTAL files: 61388

注意:manifest 放在 jyd_digital 目录,不在项目目录里
项目目录下会生成jyd_heygem_manifest.json

✅ 在【新服务器】新建目录:jyd_heygem
目录下新建文件:receiver_9501.py
import socket, os, struct
HOST = ''
PORT = 9501
BASE = os.getcwd()
CHUNK = 1024 * 1024 # 1MB
def recv_exact(conn, n):
buf = b''
while len(buf) < n:
chunk = conn.recv(n - len(buf))
if not chunk:
return None
buf += chunk
return buf
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)
print("READY on", PORT)
conn, addr = s.accept()
print("Connected", addr)
count = 0
while True:
hdr = recv_exact(conn, 4)
if hdr is None:
break
path_len = struct.unpack("!I", hdr)[0]
path_bytes = recv_exact(conn, path_len)
if path_bytes is None:
break
path = path_bytes.decode("utf-8", errors="replace")
size_bytes = recv_exact(conn, 8)
if size_bytes is None:
break
size = struct.unpack("!Q", size_bytes)[0]
full_path = os.path.join(BASE, path)
os.makedirs(os.path.dirname(full_path), exist_ok=True)
remaining = size
with open(full_path, "wb") as f:
while remaining > 0:
chunk = conn.recv(min(CHUNK, remaining))
if not chunk:
break
f.write(chunk)
remaining -= len(chunk)
# 关键:ACK
conn.sendall(b"OK")
count += 1
if count % 50 == 0:
print("Received files:", count)
print("DONE total:", count)
conn.close()
s.close()
在jyd_heygem目录下运行
python3 receiver_9501.py
你必须看到这两行:
READY on 9501
Connected ('188.18.18.149', xxxxx)

接收完成

✅ 在【源服务器】新建文件:sender_9501.py
import socket
import os
import struct
import json
import time
# ================== 配置区 ==================
HOST = "188.18.18.149" # 目标服务器 IP
PORT = 9501 # 必须和 receiver 一致
BASE = "jyd_heygem" # 要发送的目录
MANIFEST = "jyd_heygem_manifest.json"
CHUNK = 1024 * 1024 # 1MB
# ============================================
def send_file(sock, base, rel_path, size):
"""
发送单个文件(分块)
"""
full_path = os.path.join(base, rel_path)
# 发送头
sock.sendall(struct.pack("!I", len(rel_path)))
sock.sendall(rel_path.encode("utf-8"))
sock.sendall(struct.pack("!Q", size))
remaining = size
with open(full_path, "rb") as f:
while remaining > 0:
data = f.read(min(CHUNK, remaining))
if not data:
raise IOError("Unexpected EOF while reading file")
sock.sendall(data)
remaining -= len(data)
def main():
# 读取 manifest
with open(MANIFEST, "r") as f:
files = json.load(f)
total = len(files)
print(f"[INFO] Manifest loaded: {total} files")
# 建立连接
sock = socket.socket()
sock.connect((HOST, PORT))
print(f"[INFO] Connected to {HOST}:{PORT}")
sent = 0
skipped = 0
start_time = time.time()
for item in files:
rel_path = item["path"]
size = item["size"]
full_path = os.path.join(BASE, rel_path)
# 文件可读性检查
if not os.path.exists(full_path):
print(f"[SKIP] Missing file: {rel_path}")
skipped += 1
continue
try:
send_file(sock, BASE, rel_path, size)
except Exception as e:
print(f"[ERROR] Sending {rel_path}: {e}")
skipped += 1
continue
# 等待 ACK
try:
ack = sock.recv(2)
except Exception as e:
print(f"[ERROR] ACK failed on {rel_path}: {e}")
break
if ack != b"OK":
print(f"[ERROR] Invalid ACK on {rel_path}: {ack}")
break
sent += 1
if sent % 50 == 0:
elapsed = int(time.time() - start_time)
print(f"[PROGRESS] Sent {sent}/{total} files | {elapsed}s elapsed")
sock.close()
print("===================================")
print(f"[DONE] Sent: {sent}")
print(f"[DONE] Skipped: {skipped}")
print(f"[DONE] Manifest total: {total}")
print("===================================")
if __name__ == "__main__":
main()
运行:pytohn sender_9501.py

发送完成

三、启动顺序(非常重要)
✅ 1️⃣ 先在目标服务器启动接收端
python3 receiver_9501.py
必须看到:
READY on 9501
✅ 2️⃣ 再在源服务器启动发送端
python3 sender_9501.py
你应该看到类似:
[INFO] Manifest loaded: 12345 files
[INFO] Connected to 188.18.18.149:9501
[PROGRESS] Sent 50/12345 files | 12s elapsed
[PROGRESS] Sent 100/12345 files | 25s elapsed ...
[DONE] Sent: 12345 [DONE] Skipped: 0 [DONE] Manifest total: 12345
四、最终一致性校验(测试"项目能不能跑")
