2014-09-05 19 views
3

我正在與asyncio.Protocol服務器一起工作,其目的是讓客戶端調用服務器,但等待,直到服務器響應並且數據爲在停止客戶端循環之前返回。如何讓我的asyncio客戶端調用套接字服務器並等待響應

根據asyncio doc回聲客戶端和服務器:https://docs.python.org/3/library/asyncio-protocol.html#protocol-example-tcp-echo-server-and-client,transport.write(...)的結果在被調用時立即返回。

通過經驗,呼籲loop.run_until_complete(coroutine)失敗RuntimeError: Event loop is running.

服務器的data_received()方法運行asyncio.sleep(n)沒有任何效力,要麼。

yield from asyncio.sleep(n) and yield from asyncio.async(asyncio.sleep(n)) in data_received() both the hang the server。

我的問題是,我如何讓我的客戶端在回饋控制之前等待服務器寫回應?

+0

你想剛剛從服務器獲取答案後關閉客戶端?或者是其他東西? – 2014-09-06 09:42:11

+0

是的,我希望客戶端和服務器之間的功能就像典型的同步方法調用一樣,儘管它是非阻塞的 – NuclearPeon 2014-09-07 21:51:57

回答

3

我想永遠不要直接使用傳輸/協議對。

asyncio具有用於高級編程的Streams API。

客戶端代碼可以是這樣的:

@asyncio.coroutine 
def communicate(): 
    reader, writer = yield from asyncio.open_connection(HOST, PORT) 
    writer.write(b'data') 
    yield from writer.drain() 
    answer = yield from reader.read() 
    # process answer, maybe send new data back to server and wait for answer again 
    writer.close() 
3

您不必更改客戶端代碼。

echo-client.py

#!/usr/bin/env python3.4 
import asyncio 

class EchoClient(asyncio.Protocol): 
    message = 'Client Echo' 

    def connection_made(self, 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) 
loop.run_until_complete(coro) 
loop.run_forever() 
loop.close() 

技巧是你的代碼(包括self.transport方法)放入一個協程,並使用wait_for()方法,與yield from聲明語句的前面要求他們返回的值,或者說,這些需要一段時間才能完成:

echo-server.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.sleeper()) 
     result = asyncio.wait_for(fut, 60) 

    @asyncio.coroutine 
    def sleeper(self): 
     yield from asyncio.sleep(2) 
     self.transport.write("Hello World".encode()) 
     self.transport.close() 

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-server.py然後echo-client.py,客戶端將等待2秒鐘,如asyncio.sleep確定,然後停止。

相關問題