2015-03-16 13 views
13

Python 3 asyncio kitaplığı hakkında bilgi edindim ve küçük bir sorunla karşılaştım. EchoServer örneğini, python belgelerinden, istemcinin gönderdiği şeyleri değil, kullanıcı girdisini istemek üzere uyarlamaya çalışıyorum.python asyncio.create_server örneği kullanarak kullanıcı girişi için istemi

Sadece girdi() için bir çağrı eklemek kadar kolay olacağını düşündüm, ancak elbette giriş(), sorunlara neden olan kullanıcı girişi olana kadar engellenecektir.

İdeal olarak, sunucunun "söyleme" ye sahip olmadığı durumlarda bile istemciden veri almaya devam etmek istiyorum. Her bağlantı sunucunun sohbet ettiği bir sohbet istemcisine benziyor. Her bir bağlantıya-ve-geçiş yapabilmeyi ve stdin'den gerektiği gibi girdi gönderebilmeyi isterdim. Neredeyse bir P2P sohbet istemcisi gibi.

aşağıdaki değiştirilmiş EchoServer kodunu düşünün:

Ben sunucu tarafında giriş formu Stdin alma hakkında gitmek ve göndermek için hangi bağlantı belirtmek istiyorum nasıl
import asyncio 

class EchoServerClientProtocol(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): 
     message = data.decode() 
     print('Data received: {!r}'.format(message)) 

     reply = input() 
     print('Send: {!r}'.format(reply)) 
     self.transport.write(reply.encode()) 

     #print('Close the client socket') 
     #self.transport.close() 

loop = asyncio.get_event_loop() 
# Each client connection will create a new protocol instance 
coro = loop.create_server(EchoServerClientProtocol, '127.0.0.1', 8888) 
server = loop.run_until_complete(coro) 

# Serve requests until CTRL+c is pressed 
print('Serving on {}'.format(server.sockets[0].getsockname())) 
try: 
    loop.run_forever() 
except KeyboardInterrupt: 
    pass 

# Close the server 
server.close() 
loop.run_until_complete(server.wait_closed()) 
loop.close() 

hala bağlı müşterilerinden gelen girdileri alırken?

cevap

9

Sen Stdin verileri data_received yönteme alınan geçirmek için bir asyncio.Queue kullanmak sonra veri sys.stdin geçerli çalıştırılacak loop.add_reader zamanlamayı geri arama kullanabilirsiniz ve :

import sys 
import asyncio 


def got_stdin_data(q): 
    asyncio.async(q.put(sys.stdin.readline())) 

class EchoServerClientProtocol(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): 
     message = data.decode() 
     print('Data received: {!r}'.format(message)) 
     fut = asyncio.async(q.get()) 
     fut.add_done_callback(self.write_reply) 

    def write_reply(self, fut): 
     reply = fut.result() 
     print('Send: {!r}'.format(reply)) 
     self.transport.write(reply.encode()) 

     #print('Close the client socket') 
     #self.transport.close() 

q = asyncio.Queue() 
loop = asyncio.get_event_loop() 
loop.add_reader(sys.stdin, got_stdin_data, q) 
# Each client connection will create a new protocol instance 
coro = loop.create_server(EchoServerClientProtocol, '127.0.0.1', 8888) 
server = loop.run_until_complete(coro) 

# Serve requests until CTRL+c is pressed 
print('Serving on {}'.format(server.sockets[0].getsockname())) 
try: 
    loop.run_forever() 
except KeyboardInterrupt: 
    pass 

# Close the server 
server.close() 
loop.run_until_complete(server.wait_closed()) 
loop.close() 

sadece zor biraz nasıl Queue.put/Queue.get yöntemlerini çağırın; her ikisi de, geri aramada veya Protocol örnek yöntemlerinde yield from kullanılarak çağrılamayan koroutindir. Bunun yerine, bunları asyncio.async kullanarak olay döngüsü ile zamanlamak ve daha sonra get() çağrısından aldığımız yanıtı işlemek için add_done_callback yöntemini kullanın.

+0

Bunun gibi bir sıra kullanmam gerektiğinden şüphelenildi, ancak nasıl uygulanacağından emin değildim. Harika yanıt için teşekkürler! Güzel çalışıyor. – RG5

İlgili konular