0

刚刚找到了帮助我调整 pyftpdlib 模块的 Queue 模块。我正在运行一个非常严格的 FTP 服务器,我的目标是限制可上传的文件名。这是为了防止人们上传他们想要的任何东西(它实际上是上传客户端的后端,而不是完整的 FTP 服务器)。

我在 ftpserver 授权器中有这个:

def fetch_worlds(queue, username):
    while queue.empty():
        worlds = models.World.objects.filter(is_synced=True, user__username=username)
        print worlds

        queue.put(worlds, timeout=1)

class FTPAuthorizer(ftpserver.DummyAuthorizer):

    def __init__(self):
        self.q = Queue.Queue()
        self.t = None # Thread
        self.world_item = None

    def has_perm(self, username, perm, path=None):

        print "Checking permission\n"

        if perm not in ['r','w']:
            return False

        # Check world name        
        self.t = threading.Thread(target=fetch_worlds, args=(self.q, username))
        self.t.daemon = True
        self.t.start()

        self.world_item = self.q.get() 

        print "WORLDITEM: %s" % self.world_item

        if path is not None:
            path = os.path.basename(path)
            for world in self.world_item:
                test = "{0}_{1}.zip".format(username, world.name)
                if path == test:
                    print "Match on %s" % test
                    return True

        return False

我的问题是,在服务器启动后,我第一次存储文件时,它会执行初始数据库调用并正确获取所有世界。但是当我再添加另一个世界时(例如,设置is_synced=True一个,它仍然从 .has_perm() 返回旧数据,self.q.get()每次上传文件时都会调用它,它需要返回实时数据(检查是否允许文件)。

例如,全新的服务器:

  1. STOR 文件.zip,self.q.get()返回<World1, World2>
  2. 通过其他方法等更新数据库
  3. STOR file2.zip, inside fetch_worldsprint worlds返回<World1, World2, World3>self.q.get()返回<World1, World2>

刚刚找到 Queue 模块,它似乎会有所帮助,但我无法正确实现。

(也无法添加标签pyftpdlib

4

1 回答 1

0

我认为这就是这里可能发生的事情:

  1. has_perm被调用时,您创建一个Thread将查询数据库(?)以将元素添加到队列
  2. 调用start数据库后需要一些时间
  3. 同时在您输入的主线程中,q.get这将阻塞。
  4. db 调用完成并将结果添加到队列中
  5. 并立即被阻塞再次从队列中删除q.get
  6. 队列现在是空的,您的线程再次进入while循环并再次执行相同的查询并将结果放入队列中。
  7. 下一次调用q.get将返回它而不是它所期望的。

你看,你可能在这里有一个竞争条件,这已经从你在循环中向队列中添加一些东西而你在拉动时没有循环的事实中很明显。您还假设您从队列中获得的元素是您之前放入它的结果。这不一定是真的。
如果您调用has_perm两次,这将导致两次调用,fetch_worlds并且有可能queue.empty()检查其中一个调用失败。所以只有一个结果会被放入队列。现在你有两个线程在等待q.get,但只有一个会得到结果,而另一个等待直到一个准备好......

has_perm看起来它应该是一个阻塞调用。

于 2012-05-12T11:39:28.243 回答