Python中同步盘的本地与服务器同步是如何实现的?

毕设想做一个类似坚果云的同步盘(简略粗糙版),web 端 打算用 Django 或者 Flask。

但是本地与服务器同步这里遇到了个问题:因为需要运行一个 web 端,所以本地与服务端同步、传输文件是直接向 web 发起 http 请求还是再在服务端写一个 socket 来处理?

不知道我这样描述有没有清楚...感觉就是同步、传输文件是用 BS 还是 CS ?

希望 v 站的前辈们给点想法哈


Python中同步盘的本地与服务器同步是如何实现的?
9 回复

linux 自带的 rsync 就能满足大多数的同步需求 (


Python里实现同步盘的核心是双向同步算法,通常用差异检测+冲突解决的思路。下面是一个简化但可运行的本地/服务器双向同步示例:

import os
import hashlib
import shutil
from pathlib import Path
import json
from datetime import datetime

class SimpleSync:
    def __init__(self, local_dir, server_dir):
        self.local_dir = Path(local_dir)
        self.server_dir = Path(server_dir)
        self.state_file = self.local_dir / '.sync_state.json'
        
    def get_file_hash(self, filepath):
        """计算文件MD5哈希"""
        hash_md5 = hashlib.md5()
        with open(filepath, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                hash_md5.update(chunk)
        return hash_md5.hexdigest()
    
    def scan_directory(self, directory):
        """扫描目录生成文件状态快照"""
        snapshot = {}
        for root, _, files in os.walk(directory):
            for file in files:
                full_path = Path(root) / file
                rel_path = full_path.relative_to(directory)
                stat = full_path.stat()
                snapshot[str(rel_path)] = {
                    'mtime': stat.st_mtime,
                    'size': stat.st_size,
                    'hash': self.get_file_hash(full_path)
                }
        return snapshot
    
    def detect_changes(self, old_state, new_state):
        """检测文件变化:新增、修改、删除"""
        changes = {'new': [], 'modified': [], 'deleted': []}
        
        # 检测新增和修改
        for file in new_state:
            if file not in old_state:
                changes['new'].append(file)
            elif (new_state[file]['mtime'] > old_state[file]['mtime'] or 
                  new_state[file]['hash'] != old_state[file]['hash']):
                changes['modified'].append(file)
        
        # 检测删除
        for file in old_state:
            if file not in new_state:
                changes['deleted'].append(file)
                
        return changes
    
    def sync_file(self, src_dir, dst_dir, rel_path):
        """同步单个文件"""
        src = src_dir / rel_path
        dst = dst_dir / rel_path
        
        # 确保目标目录存在
        dst.parent.mkdir(parents=True, exist_ok=True)
        
        # 复制文件(实际应用应该用增量传输)
        shutil.copy2(src, dst)
        print(f"同步: {rel_path}")
    
    def delete_file(self, directory, rel_path):
        """删除文件"""
        target = directory / rel_path
        if target.exists():
            target.unlink()
            print(f"删除: {rel_path}")
    
    def run_sync(self):
        """执行双向同步"""
        # 加载上次同步状态
        old_state = {}
        if self.state_file.exists():
            with open(self.state_file, 'r') as f:
                old_state = json.load(f)
        
        # 扫描当前状态
        local_state = self.scan_directory(self.local_dir)
        server_state = self.scan_directory(self.server_dir)
        
        # 双向检测变化
        local_changes = self.detect_changes(old_state, local_state)
        server_changes = self.detect_changes(old_state, server_state)
        
        # 同步:服务器 -> 本地
        for change_type in ['new', 'modified']:
            for file in server_changes[change_type]:
                self.sync_file(self.server_dir, self.local_dir, file)
        
        # 同步:本地 -> 服务器  
        for change_type in ['new', 'modified']:
            for file in local_changes[change_type]:
                self.sync_file(self.local_dir, self.server_dir, file)
        
        # 处理删除(简单策略:双向删除)
        for file in set(server_changes['deleted'] + local_changes['deleted']):
            self.delete_file(self.local_dir, file)
            self.delete_file(self.server_dir, file)
        
        # 保存新状态(取并集)
        merged_state = {**local_state, **server_state}
        with open(self.state_file, 'w') as f:
            json.dump(merged_state, f, indent=2)
        
        print("同步完成")

# 使用示例
if __name__ == "__main__":
    # 创建测试目录
    local = "./test_local"
    server = "./test_server"
    Path(local).mkdir(exist_ok=True)
    Path(server).mkdir(exist_ok=True)
    
    # 创建测试文件
    (Path(local) / "test.txt").write_text("Hello Local")
    (Path(server) / "server.txt").write_text("Hello Server")
    
    # 执行同步
    syncer = SimpleSync(local, server)
    syncer.run_sync()

关键实现要点:

  1. 状态快照:通过文件哈希(MD5)、修改时间、文件大小建立文件指纹
  2. 差异检测:对比前后状态识别增/删/改
  3. 双向同步:分别检测两端变化并相互复制
  4. 冲突处理:示例采用“最后修改者胜”,实际需要更复杂策略(如版本号、用户确认)

实际应用改进方向:

  • 用rsync算法进行增量传输
  • 添加文件锁避免同时修改
  • 实现版本历史和冲突合并
  • 使用inotify实时监控代替轮询

这个示例展示了同步的核心逻辑,真实系统(如Nextcloud、Syncthing)会在此基础上增加网络传输、加密、压缩等模块。

一句话建议:核心是维护文件状态机并处理冲突。

BS 还有 websocket 实现实时通讯呢。答案肯定是都可以啦

自己实现一个 rsync, 我记得 zlib 有相关的函数

怎么都行 你甚至可以直接内嵌个 rsync

都可以 你甚至可以直接把整个文件 post 上去,然后服务端替换掉硬盘上的文件

我之前写过一个 python 的同步盘服务器是这么干的(





感谢指点!



这样的话服务端同步到客户端怎么做呢

#6 我当初偷懒直接搞了客户端定期检查,应该有更好的方案比如 websocket 之类的

回到顶部