2

TCPTwistedとPygameを使用して、シンプルなclinet / serverゲームを開発しようとしていますが、クライアントにデータを送信するのに問題があります。Twistedでは、複数の応答を続けて送信することはできません。それが私がやろうとしていることです:

メソッドwitchにプレーヤーのステータス変更を処理させ、他のクライアントに再送信します。

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メソッド(を使用して1秒/ 30ごとに呼び出されますLoopingCall)は、すべてのゲームのものを計算してプレーヤーに送信するだけです。これらの2つの関数は相互にブロックし、別々に正常に機能しますが、連携すると、一方のデータのみが宛先に到達します。また、このようなものは機能しません:

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)
4

1 に答える 1

4

サーバーには、リモートで任意のコードが実行される脆弱性があります。

ネットワークから受信したデータの選択を解除する必要がある状況は、あるとしてもごくわずかです。そうすることで、あらゆるピアが任意の、おそらく悪意のある目的でサーバーを乗っ取ることができます。 ピクルスのドキュメントにある大きな赤いボックスに注意してください

この深刻なセキュリティの問題とは別に、送信される最初のデータのみが解釈されるという問題は、2つのデータがネットワークを通過するときに結合されることが原因である可能性があります。受信コードには適切なフレーミングサポートがないため、2つのメッセージがあることを認識できません。たまたま、pickleは最初のメッセージからデータをロードし、その後、2番目のメッセージを表す余分なデータを無視して、そのデータを事実上フロアにドロップします。

AMPなど、より表現力のあるプロトコル(フレーム化されていないピクルス文字列を転送するベアTCPよりも表現力の高いプロトコル)に切り替えると、セキュリティの問題とフレーミングの問題の両方を解決できます。

于 2013-01-29T20:25:40.300 に答える