刚刚找到了帮助我调整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
我的问题是,在服务器启动后,我第一次存储文件时,它会进行初始数据库调用并正确地获取所有世界。但是当我然后添加另一个世界(例如,将is_synced=True
设置为一个世界时,它仍会返回self.q.get()
中的旧数据。每次上传文件时都会调用has_perm(),并且需要返回实时数据(检查是否允许文件)。
例如,全新的服务器:
self.q.get()
返回<World1, World2>
fetch_worlds
内,print worlds
返回<World1, World2, World3>
但self.q.get()
返回<World1, World2>
刚刚找到了Queue模块,看起来它会有所帮助,但我无法正确实现。
(也无法添加标记pyftpdlib
)
答案 0 :(得分:0)
我认为这是可能发生的事情:
has_perm
时,您创建一个Thread
来查询数据库(?)以将元素添加到队列中start
后,对数据库的调用将花费一些时间q.get
,这将阻止。q.get
q.get
的下一次调用将返回该内容而不是预期内容。你知道,你可能在这里遇到一个竞争条件,因为你在循环中没有循环时向循环中添加一些东西已经很明显了。
你也假设你从队列中得到的元素是你之前放到它上面的结果。这不一定是真的。
如果您拨打has_perm
两次,这将导致两次调用fetch_worlds
,其中一次呼叫的queue.empty()
检查失败。所以只有一个结果会被放入队列中。现在你有两个线程等待q.get
,但只有一个会得到一个结果,而另一个等待直到一个准备就绪......
has_perm
看起来应该是阻止通话。