服务器损坏,数据迁移,只有一个链接窗口的情况下

🔹 阶段 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

四、最终一致性校验(测试"项目能不能跑")

相关推荐
SkyWalking中文站13 小时前
认识 Horizon UI · 5/17:3D 基础设施地图
运维·监控·自动化运维
SkyWalking中文站1 天前
认识 Horizon UI · 1/17:SkyWalking 新一代可观测性控制台
运维·前端·监控
雪梨酱QAQ2 天前
Kubeneters HA Cluster部署
运维
江华森2 天前
Spring Cloud 微服务全栈实战:从 Eureka 到 Docker Compose 一文贯通
运维
江华森2 天前
Matplotlib 数据绘图基础入门
运维
江华森2 天前
NumPy 数值计算基础入门
运维
乘云数字DATABUFF6 天前
5分钟部署开源APM Databuff:OpenTelemetry全链路追踪入门实战
运维·后端
荣--8 天前
一键部署不是为了省时间 —— 它是把"买来的 PaaS"变成"自己的平台"的拐点
运维·zabbix·工程化·一键部署·平台化·边界设计
江华森8 天前
动手实战学 Docker — 从零到集群编排完全指南
运维
Avan_菜菜8 天前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https