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!

Reply via email to