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)
