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

🔹 阶段 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 小时前
CANN开源项目深度实践:基于amct-toolkit实现自动化模型量化与精度保障策略
运维·开源·自动化·cann
较劲男子汉6 小时前
CANN Runtime零拷贝传输技术源码实战 彻底打通Host与Device的数据传输壁垒
运维·服务器·数据库·cann
wypywyp6 小时前
8. ubuntu 虚拟机 linux 服务器 TCP/IP 概念辨析
linux·服务器·ubuntu
风流倜傥唐伯虎6 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
Doro再努力6 小时前
【Linux操作系统10】Makefile深度解析:从依赖推导到有效编译
android·linux·运维·服务器·编辑器·vim
senijusene6 小时前
Linux软件编程:IO编程,标准IO(1)
linux·运维·服务器
不像程序员的程序媛6 小时前
Nginx日志切分
服务器·前端·nginx
忧郁的橙子.7 小时前
02-本地部署Ollama、Python
linux·运维·服务器
醇氧7 小时前
【linux】查看发行版信息
linux·运维·服务器
No8g攻城狮7 小时前
【Linux】Windows11 安装 WSL2 并运行 Ubuntu 22.04 详细操作步骤
linux·运维·ubuntu