重组程序使用asyncio

时间:2015-03-11 21:34:53

标签: python sockets python-3.x network-programming pygame

目前,我有一款使用socket模块同步进行网络连接的游戏。

结构如下:

服务器:

while True:
    add_new_clients()
    process_game_state()
    for client in clients:
        send_data(client)
        get_data_from(client)

客户端:

connect_to_server()
while True:
    get_data_from_server()
    process_game_state()
    draw_to_screen()
    send_input_to_server()

我想将网络代码替换为使用比socket更高级别模块的网络代码,例如asyncio或gevent。但是,我不知道该怎么做。

我见过的所有例子的结构都是这样的:

class Server:
    def handle_client(self, connection):
        while True:
            input = get_input(connection)
            output = process(input)
            send(connection, output)

然后为每个加入的客户端使用线程或其他东西并行调用handle_client

如果可以单独处理客户端,则此工作正常。但是,我仍然希望保持游戏循环类型结构,其中处理仅在一种情况下发生 - 我不希望必须检查每个客户端的冲突等。我该怎么做?

1 个答案:

答案 0 :(得分:2)

我假设您了解如何使用协议创建服务器以及异步范例如何工作。

您需要的只是分解的事件循环转换为处理程序

让我们看看服务器案例和客户案例:

服务器案例

客户端(服务器端)

您需要创建一个我们称之为协议的东西,它将用于创建服务器并充当每个实例=客户端的模式:

class ClientProtocol(asyncio.Protocol):
    def connection_made(self, transport):
        # Here, we have a new player, the transport represent a socket.
        self.transport = transport


    def data_received(self, data):
        packet = decode_packet(data) # some function for reading packets
        if packet.opcode == CMSG_MOVE: # opcode is a operation code.
            self.player.move(packet[0]) # packet[0] is the first "real" data.
            self.transport.write("OK YOUR MOVE IS ACCEPTED") # Send back confirmation or whatever.

好的,现在您已了解如何与客户合作。

游戏状态

之后,您需要每X ms处理一次游戏状态:

def processGameState():
    # some code...
    eventLoop.call_later(0.1, processGameState) # every 100 ms, processGameState is called.

在某些时候,你将在初始化时调用processGameState,它会告诉eventLoop在100毫秒之后调用processGameState(这可能不是理想的方式,但它是一个像另一个想法

至于向客户端发送新数据,您只需要存储ClientProtocol的列表,并为每个传输写一个简单的。

显然删除了get_data_from,因为我们在data_received的{​​{1}}方法中异步接收了所有数据。

这是如何将所有同步代码重构为异步代码的草图。您可能想要添加身份验证和其他一些事情,如果这是您第一次使用异步范例,我建议您尝试使用Twisted而不是asyncio:Twisted可能比asyncio(但是asyncio)更有记录和解释与Twisted完全相同,因此您可以每次都切换回来。

客户案例

这里也差不多。

但是,您可能需要注意绘制方式以及如何管理输入。您可能需要最终使用另一个线程来调用输入处理程序,并使用另一个线程以恒定的帧速率绘制到屏幕。

结论

在异步中思考起初非常困难。

但值得付出努力。

请注意,即使我的方法可能不是最好的或适合游戏。我只是觉得我会这样做,请花点时间测试你的代码并对其进行分析。 检查你是否在同一个函数中没有混合同步和异步代码而没有使用deferToThread(或其他帮助者)正确处理,它会销毁你游戏的表现< /强>