0

pyftpdlib モジュールの適応に役立つ Queue モジュールを見つけました。私は非常に厳密な FTP サーバーを実行しています。私の目標は、アップロードできるファイル名を制限することです。これは、ユーザーが自分の好きなものをアップロードできないようにするためです (実際にはアップロード クライアントのバックエンドであり、完全な FTP サーバーではありません)。

私は ftpserver Authorizer にこれを持っています:

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

私の問題は、サーバーの起動後、初めてファイルを STOR すると、最初の db 呼び出しが行われ、すべての世界が適切に取得されることです。しかし、次に別のワールドを追加すると (たとえば、is_synced=True1 つに設定しても、self.q.get().has_perm() はファイルがアップロードされるたびに呼び出され、ライブ データを返す必要があります (ファイルが許可されているかどうかを確認するため))。 )。

たとえば、真新しいサーバー:

  1. STOR file.zip、self.q.get()戻り値<World1, World2>
  2. 他の方法などでデータベースを更新します
  3. STOR file2.zip、内部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、期待するものの代わりにそれを返します。

ほら、ここで競合状態が発生する可能性があります。これは、プルするときにループがないときに、ループ内のキューに何かを追加しているという事実からすでに明らかです。また、キューから取得した要素は、以前にキューに入れたことの結果であると想定します。それは真実である必要はありません。
2 回呼び出すと、呼び出しがhas_perm2 回発生し、呼び出しの 1 つのチェックが失敗するfetch_worlds可能性があります。queue.empty()そのため、1 つの結果のみがキューに入れられます。で 2 つのスレッドが待機していますがq.get、結果を取得できるのは 1 つだけで、もう 1 つのスレッドは準備が整うまで待機しています...

has_permとにかくブロッキングコールであるように見えます。

于 2012-05-12T11:39:28.243 に答える