如何在Python中使用tulip / asyncio创建中继服务器?

时间:2014-01-22 22:09:02

标签: python asynchronous python-asyncio

我有example echo server

import asyncio

class EchoServer(asyncio.Protocol):
    def connection_made(self, transport):
        peername = transport.get_extra_info('peername')
        print('connection from {}'.format(peername))
        self.transport = transport

    def data_received(self, data):
        self.transport.write(data)
        # Client piece goes here

loop = asyncio.get_event_loop()
coro = loop.create_server(EchoServer, '127.0.0.1', 8888)
server = loop.run_until_complete(coro)
print('serving on {}'.format(server.sockets[0].getsockname()))

try:
    loop.run_forever()
except KeyboardInterrupt:
    print("exit")
finally:
    server.close()
    loop.close()

我正在尝试做的是添加一个客户端部分,我评论说它将连接到新服务器并从该方式发送数据。有echo client,但我需要一个看起来像这样的过程:

    +-----------+    +-----------+    +--------------+
    | My Server |    | My Client |    | Other Server |
    +-----------+    +-----------+    +--------------+
          |                |                 |
 ===>Get some data         |                 |
          |                |                 |
      Send data ---------->|                 |
          |                |                 |
          |            Send data ----------->|
          |                |                 |
          |                |              Do Stuff
          |                |                 |
          |                | <-----------Send Data
          |                |                 |
          | <--------- Send data             |
          |                |                 |
 <=== Send data            |                 |
          |                |                 |
          |                |                 |
          |                |                 |
          |                |                 |

显然我可以同步执行此操作,但我正在尝试使client -> other server位异步,并且我并没有真正弄清楚如何使用asyncio方法在我的服务器块之间进行通信和客户一块。

我需要在这做什么?

1 个答案:

答案 0 :(得分:11)

这是一个简单的代理,允许您wget 127.0.0.1:8888并从谷歌获取HTML回复:

import asyncio

class Client(asyncio.Protocol):

    def connection_made(self, transport):
        self.connected = True
        # save the transport
        self.transport = transport

    def data_received(self, data):
        # forward data to the server
        self.server_transport.write(data)

    def connection_lost(self, *args):
        self.connected = False

class Server(asyncio.Protocol):
    clients = {}
    def connection_made(self, transport):
        # save the transport
        self.transport = transport

    @asyncio.coroutine
    def send_data(self, data):
        # get a client by its peername
        peername = self.transport.get_extra_info('peername')
        client = self.clients.get(peername)
        # create a client if peername is not known or the client disconnect
        if client is None or not client.connected:
            protocol, client = yield from loop.create_connection(
                Client, 'google.com', 80)
            client.server_transport = self.transport
            self.clients[peername] = client
        # forward data to the client
        client.transport.write(data)

    def data_received(self, data):
        # use a task so this is executed async
        asyncio.Task(self.send_data(data))

@asyncio.coroutine
def initialize(loop):
    # use a coroutine to use yield from and get the async result of
    # create_server
    server = yield from loop.create_server(Server, '127.0.0.1', 8888)

loop = asyncio.get_event_loop()

# main task to initialize everything
asyncio.Task(initialize(loop))

# run
loop.run_forever()