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

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

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

相关推荐
竹之却3 分钟前
Ubuntu 系统安装 Ollama 教程
linux·运维·ubuntu·ollama
珠海西格3 分钟前
4 月 1 日起执行分布式光伏监控新规,直接影响从业者与项目收益
大数据·运维·服务器·分布式·能源
怀旧诚子1 小时前
timeshift之Fedora43设置,已在VM虚拟机验证,待真机验证。
java·服务器·数据库
sdm0704273 小时前
yum和开发工具vim/gcc
linux·服务器·centos
zhaoyufei1333 小时前
RK3568-11.0 设置WiFi p2p静态IP
服务器·tcp/ip·p2p
Leinwin8 小时前
OpenClaw 多 Agent 协作框架的并发限制与企业化规避方案痛点直击
java·运维·数据库
2401_865382508 小时前
信息化项目运维与运营的区别
运维·运营·信息化项目·政务信息化
漠北的哈士奇8 小时前
VMware Workstation导入ova文件时出现闪退但是没有报错信息
运维·vmware·虚拟机·闪退·ova
如意.7599 小时前
【Linux开发工具实战】Git、GDB与CGDB从入门到精通
linux·运维·git
运维小欣9 小时前
智能体选型实战指南
运维·人工智能