Twisted 中的多重响应

Posted

技术标签:

【中文标题】Twisted 中的多重响应【英文标题】:Multiple responses in Twisted 【发布时间】:2013-01-13 07:57:56 【问题描述】:

我正在尝试使用 Twisted 和 Pygame 开发简单的TCP 客户端/服务器游戏,但我在向客户端发送数据时遇到了困难。 Twisted 不允许我连续发送多个回复。这就是我想要做的:

我有方法可以处理播放器状态更改并将它们重新发送给其他客户端:

def handle_stateChanged(self, data):
    #get playerState from client and override local copy of player
    #check if all players are ready
    #if needed, change gameState form 'inLOBBY' to 'inGAME'
    #if gameState == 'inGAME', start 'proceed' method (see below)
    #send message about player and game state to others

proceed 方法(使用LoopingCall 每1s/30 调用一次)只需计算所有游戏内容并将其发送给玩家。这两个函数相互阻塞,单独工作得很好,但是当它们一起工作时,只有其中一个函数的数据到达目的地。像这样的东西也不起作用:

def dataRecived(self, data):
    ...
    sendData(data1) #only data1 is delivered
    sendData(data2)
    ...  

我不知道这是 TCP 的工作方式还是我对 Twisted 缺乏了解。 我应该如何向客户端发送更新并在后台处理用户输入?

编辑:

class Server(Protocol):
    def __init__(self, factory):
        self.factory = factory
        self.player = None #when connection is made here goes my player class
        self.world = factory.world
        ...
        self.factory.loop = LoopingCall(self.proceed)

    def dataReceived(self, data):
        data = pickle.loads(data)
        #this calls 'handle_stateChanged'
        getattr(self, 'handle_'.format(data['header']))(data) #data[header] = 'stateChanged'

    def handle_stateChanged(self, data):      
        isReady = data['isReady']
        self.player.isReady = isReady

        if isReady:
            count = 0
            for connection in self.factory.connections.values():
                if connection.player.isReady:
                    count += 1

            if count == len(self.factory.connections) and count > 1 and self.world.state == 'inLOBBY':
                self.world.state = 'inGAME'
                self.world.playersDistribution(self.factory.connections)
                self.factory.loop.start(1 / 30)

        data['state'] = self.world.state
        data['players'] = self.getPlayers()        
        self.sendToOthers(data)

    def sendToOthers(self, data, omitId = None):
        connections = self.factory.connections

        for key in connections.keys():
            if key != omitId:
                connections[key].sendData(data)

    def proceed(self):
        #It's only a prototype of my method. 
        #The point is that the client keep getting
        #'test' and data from self.sendToOthers(data) in handle_stateChanged
        #is not being delivered even if the method (handle_stateChanged) is called

        if self.world.state != 'inGAME':
            return

        data = 'header' : 'message', 'body' : 'test'
        #When i comment this out, handle_stateChanged works fine and sends data
        self.sendToOthers(data)

class ServerFactory(Factory):

    def __init__(self, world):
        self.world = world
        self.connections = 

    def buildProtocol(self, addr):
        return Server(self)

【问题讨论】:

你不能在后台做任何事情,因为 Twisted 是基于事件的(除非你开始自己的线程,但不建议这样做)。你能展示更多你的代码吗? 我的意思是proceedLoopingCall调用,handle_stateChanged在每次客户端发送消息时被调用:'player is ready',所以背景是一个错误的词。我添加了一些代码。 【参考方案1】:

您的服务器存在远程任意代码执行漏洞。

在极少数情况下(如果有的话)您应该对从网络接收到的数据进行解包。这样做允许任何对等方出于任意(可能是恶意的)目的劫持您的服务器。 Note the big red box in the pickle documentation.

除了这个严重的安全问题之外,您遇到的仅发送的第一条数据被解释的问题可能是由于两条数据在穿越网络时被连接在一起造成的。您的接收代码没有适当的框架支持,因此无法判断有两条消息。碰巧pickle会从第一条消息加载数据,然后忽略代表第二条消息的额外数据,有效地将这些数据丢弃在地板上。

如果您切换到更具表现力的协议(比裸 TCP 传输未成帧的 pickle 字符串更具表现力),例如AMP,则安全问题和帧问题都可以解决。

【讨论】:

感谢您的建议!我将按照您的建议切换到 AMP,但出于学习目的,我如何为我的代码提供框架支持? itamarst.org 链接了几篇编程文章,值得一读以回答这个问题和相关问题。

以上是关于Twisted 中的多重响应的主要内容,如果未能解决你的问题,请参考以下文章

Twisted服务器/客户端之间的多个呼叫/响应消息

编写Twisted Client以向多个API调用发送循环GET请求并记录响应

运行 django 时,Twisted 服务器意外崩溃

如何使用twisted通过UDP协议发送参数

怎样安装twisted

Twisted reactor 如何与基于试验的单元测试一起工作?