The issue is that in server 1 you are trying to mix two paradigms --
data_received is a protocol callback, but your approach to calling server 2
is attempting to block. You can create the Future representing the call to
server 2 in data_receive, but you must define a helper function that writes
the response and set that helper as the Future's callback.


On Fri, Sep 5, 2014 at 2:30 PM, Dann Kettle <[email protected]> wrote:

> Hello everyone.
>
> I've been working for the past few days on a particular problem that I
> have been struggling greatly with.
>
> In theory, it should be simple:
>
>    - I have three files: client.py, serverone.py, servertwo.py
>    - I launch both servers in separate terminal windows
>    - I run client.py which then calls serverone.py, the client waits
>    until it receives the server's response, then client returns control to my
>    terminal.
>
> That much I have done successfully, as you can read in more detail on my
> stackoverflow question I made and answered here:
> http://stackoverflow.com/questions/25691062/how-do-i-get-my-asyncio-client-to-call-a-socket-server-and-waiting-for-response
>
> The problem arises when I want my client to call the serverone.py, which
> in turn calls servertwo.py and waits for its response, before sending the
> client back servertwo.py's response (through serverone.py). In the real
> world, I would use a mixture of both server responses to return the result
> back to client.
>
> I got the code working to the point where client calls serverone.py -->
> serverone.py calls servertwo.py *BUT*  ---> client receives the
> serverone.py response back and --> returns control *before* servertwo
> responds back to serverone.py.
>
> In some cases, client.py just hangs when I try a different approach.
>
> servertwo.py DOES communicate to serverone.py and vice versa, the problem
> here is synchronization I believe. I've been close to pulling my hair out.
>
>
> Any help or opinions are greatly appreciated.
>
>
> Here is the code, I'll describe the problem in more detail below:
>
> *client.py*
>
> #!/usr/bin/env python3.4
> import asyncio
>
> class EchoClient(asyncio.Protocol):
>     message = 'Client Echo'
>
>     def connection_made(self, transport):
>         self.transport = transport
>         transport.write(self.message.encode())
>         print('data sent: {}'.format(self.message))
>
>     def data_received(self, data):
>         print('data received: {}'.format(data.decode()))
>
>     def connection_lost(self, exc):
>         print('server closed the connection')
>         asyncio.get_event_loop().stop()
>
> loop = asyncio.get_event_loop()
> coro = loop.create_connection(EchoClient, '127.0.0.1', 8888)
> result = asyncio.async(coro)
> asyncio.wait_for(result, 60)
>
> loop.run_forever()
> loop.close()
>
>
> *serverone.py*
>
> #!/usr/bin/env python3.4
> import asyncio
>
> class EchoClient(asyncio.Protocol):
>     message = 'Server One Client Echo'
>
>     def connection_made(self, transport):
>         self.transport = transport
>         self.data = None
>         transport.write(self.message.encode())
>         print('client data sent: {}'.format(self.message))
>
>     def data_received(self, data):
>         print('client data received: {}'.format(data.decode()))
>         self.data = data.decode()
>
>     def connection_lost(self, exc):
>         print('client connection finished')
>         #asyncio.get_event_loop().stop()
>
> 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):
>         print('server data received: {}'.format(data.decode()))
>         fut = asyncio.async(self.callservertwo())
>         result = asyncio.wait_for(fut, 60)
>         # "result" is a generator object when it should be the result
>         self.transport.write(str(fut).encode())
>         self.transport.close()
>
>     @asyncio.coroutine
>     def callservertwo(self):
>         coro = loop.create_connection(
>             EchoClient, '127.0.0.1', 8889)
>         fut = yield from asyncio.async(coro)
>         return asyncio.wait_for(fut, 60)
>
> 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()
>
> *servertwo.py*
>
> #!/usr/bin/env python3.4
> 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):
>         print('data received: {}'.format(data.decode()))
>         fut = asyncio.async(self.server_two_says_hello())
>         asyncio.wait_for(fut, 60)
>
>     @asyncio.coroutine
>     def server_two_says_hello(self):
>         self.transport.write("Hello - ServerTwo".encode())
>         # close the socket
>         self.transport.close()
>
>
> loop = asyncio.get_event_loop()
> coro = loop.create_server(EchoServer, '127.0.0.1', 8889)
> 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()
>
> *Problem:*
>
> When I run the code, client.py immediately returns. This is what is
> returned from serverone.py:
>
> data received: Task(<callservertwo>)<PENDING>
>
> I've tried yield from's, putting things to @asyncio.coroutine decorated
> methods, but either it tries to return generators, tasks, or client.py
> hangs.
>
>
> TL;DR: I need to run client.py and have it print out the string "Hello -
> ServerTwo"
>
> Thanks for reading!
>



-- 
--Guido van Rossum (python.org/~guido)

Reply via email to