2014-11-03 4 views
1

autobahn | python 과 asyncio을 사용하여 websocket/wamp 클라이언트를 구현하려고하는데, 다소 효과가 있지만, 은 나를 벗어났습니다.autobahn asyncio와 함께 대화 형 websocket 클라이언트를 구현하려면 어떻게해야합니까?

내가 정말로하려는 것은 qt5/QML에 WAMP를 구현하는 것이지만,이 은 더 쉬운 경로처럼 보였다.

주로 온라인에서 복사 한이 단순화 된 클라이언트가 작동합니다. onJoin이 발생하면 시간 서비스를 읽습니다.

외부 소스에서이 읽기를 실행하고 싶습니다.

내가 취한 복잡한 방법은 스레드에서 asyncio 이벤트 루프를 실행 한 다음 소켓을 통해 명령을 보내서 읽기를 트리거하는 것입니다. I 지금까지 루틴/코 루틴을 어디에 두어야하는지 알 수 없으므로 리더 루틴에서 찾을 수 있습니다.

나는 이것에 관해서 더 간단한 방법이 있다고 의심하지만 아직 발견하지 못했습니다. . 제안을 환영합니다.

#!/usr/bin/python3 
try: 
    import asyncio 
except ImportError: 
    ## Trollius >= 0.3 was renamed 
    import trollius as asyncio 

from autobahn.asyncio import wamp, websocket 
import threading 
import time 
from socket import socketpair 

rsock, wsock = socketpair() 

def reader() : 
    data = rsock.recv(100) 
    print("Received:", data.decode()) 

class MyFrontendComponent(wamp.ApplicationSession): 
    def onConnect(self): 
     self.join(u"realm1") 



    @asyncio.coroutine 
    def onJoin(self, details): 
     print('joined') 
     ## call a remote procedure 
     ## 
     try: 
      now = yield from self.call(u'com.timeservice.now') 
     except Exception as e: 
      print("Error: {}".format(e)) 
     else: 
      print("Current time from time service: {}".format(now)) 



    def onLeave(self, details): 
     self.disconnect() 

    def onDisconnect(self): 
     asyncio.get_event_loop().stop() 



def start_aloop() : 
    loop = asyncio.new_event_loop() 
    asyncio.set_event_loop(loop) 
    transport_factory = websocket.WampWebSocketClientFactory(session_factory, 
        debug = False, 
        debug_wamp = False) 
    coro = loop.create_connection(transport_factory, '127.0.0.1', 8080) 
    loop.add_reader(rsock,reader) 
    loop.run_until_complete(coro) 
    loop.run_forever() 
    loop.close() 

if __name__ == '__main__': 
    session_factory = wamp.ApplicationSessionFactory() 
    session_factory.session = MyFrontendComponent 

    ## 4) now enter the asyncio event loop 
    print('starting thread') 
    thread = threading.Thread(target=start_aloop) 
    thread.start() 
    time.sleep(5) 
    print("IN MAIN") 
    # emulate an outside call 
    wsock.send(b'a byte string') 
+0

그렇다면 일부 외부 수단을 통해 클라이언트가 시간 서비스에 RPC 호출을하도록 할 수 있습니까? – dano

답변

0

loop.sock_accept을 사용하여 이벤트 루프 내에서 비동기 소켓에서 수신 대기 할 수 있습니다. 당신은 소켓 onConnect 또는 onJoin의 내부 설정에 코 루틴을 호출 할 수 있습니다 : 응답 단오에 대한

try: 
    import asyncio 
except ImportError: 
    ## Trollius >= 0.3 was renamed 
    import trollius as asyncio 

from autobahn.asyncio import wamp, websocket 
import socket 

class MyFrontendComponent(wamp.ApplicationSession): 
    def onConnect(self): 
     self.join(u"realm1") 

    @asyncio.coroutine 
    def setup_socket(self): 
     # Create a non-blocking socket 
     self.sock = socket.socket() 
     self.sock.setblocking(0) 
     self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
     self.sock.bind(('localhost', 8889)) 
     self.sock.listen(5) 
     loop = asyncio.get_event_loop() 
     # Wait for connections to come in. When one arrives, 
     # call the time service and disconnect immediately. 
     while True: 
      conn, address = yield from loop.sock_accept(self.sock) 
      yield from self.call_timeservice() 
      conn.close() 

    @asyncio.coroutine 
    def onJoin(self, details): 
     print('joined') 
     # Setup our socket server 
     asyncio.async(self.setup_socket()) 

     ## call a remote procedure 
     ## 
     yield from self.call_timeservice() 

    @asyncio.coroutine 
    def call_timeservice(self): 
     try: 
      now = yield from self.call(u'com.timeservice.now') 
     except Exception as e: 
      print("Error: {}".format(e)) 
     else: 
      print("Current time from time service: {}".format(now)) 

    ... # The rest is the same 
0

감사합니다. 내가 필요한 해결책은 아니지만 올바른 방향으로 나를 가리켰다. 예, 외부 트리거로부터 클라이언트 RPC 원격 호출을 받고 싶습니다.

나는 잘 모르겠어요하지만, (하나는 현재 구현하지만) 나

여기

내가 생각 해낸거야 특정 통화에 대한 문자열을 전달할 수 있습니다 다음 해낸 방법 우아한 그것을 입니다.

import asyncio 
from autobahn.asyncio import wamp, websocket 
import threading 
import time 
import socket 


rsock, wsock = socket.socketpair() 

class MyFrontendComponent(wamp.ApplicationSession): 
    def onConnect(self): 
     self.join(u"realm1") 

    @asyncio.coroutine 
    def setup_socket(self): 
     # Create a non-blocking socket 
     self.sock = rsock 
     self.sock.setblocking(0) 
     loop = asyncio.get_event_loop() 
     # Wait for connections to come in. When one arrives, 
     # call the time service and disconnect immediately. 
     while True: 
      rcmd = yield from loop.sock_recv(rsock,80) 
      yield from self.call_service(rcmd.decode()) 

    @asyncio.coroutine 
    def onJoin(self, details): 
     # Setup our socket server 
     asyncio.async(self.setup_socket()) 


    @asyncio.coroutine 
    def call_service(self,rcmd): 
     print(rcmd) 
     try: 
      now = yield from self.call(rcmd) 
     except Exception as e: 
      print("Error: {}".format(e)) 
     else: 
      print("Current time from time service: {}".format(now)) 



    def onLeave(self, details): 
     self.disconnect() 

    def onDisconnect(self): 
     asyncio.get_event_loop().stop() 



def start_aloop() : 
    loop = asyncio.new_event_loop() 
    asyncio.set_event_loop(loop) 
    transport_factory = websocket.WampWebSocketClientFactory(session_factory, 
        debug = False, 
        debug_wamp = False) 
    coro = loop.create_connection(transport_factory, '127.0.0.1', 8080) 
    loop.run_until_complete(coro) 
    loop.run_forever() 
    loop.close() 

if __name__ == '__main__': 
    session_factory = wamp.ApplicationSessionFactory() 
    session_factory.session = MyFrontendComponent 

    ## 4) now enter the asyncio event loop 
    print('starting thread') 
    thread = threading.Thread(target=start_aloop) 
    thread.start() 
    time.sleep(5) 
    wsock.send(b'com.timeservice.now') 
    time.sleep(5) 
    wsock.send(b'com.timeservice.now') 
    time.sleep(5) 
    wsock.send(b'com.timeservice.now') 
+0

'asyncio.sleep'과'loop.socket_sendall'을 사용하여보다'asyncio' 친숙한 방식으로'wsock' 물건을 구현할 수 있습니다. 그렇게하면 백그라운드 스레드가 필요 없습니다. 대신에, asyncio.sleep (5)와 yield from loop.sock_sendall (wsock, b'com.timeservice.now ')를 호출 한'asyncio.async'를 사용하여 동시 루틴을 예약 할 수 있습니다. – dano

+0

고마워, 나는 이것을 계속 볼 것이다. 그러나 나는 단지 며칠 동안 그것으로 일해 왔고, 아직 완전히 속도를 내고 있지 않다. 이 코드는 pyotherside 내부에서 사용되고 foreground 함수는 QML 코드에서 호출되기 때문에 백그라운드에 루프를 배치했습니다. 아마 더 나은 방법이있을 수 있으며, 시간이 지나면 더 명확해질 것이라고 생각합니다. – morris

+0

아,이 코드를 'asyncio' 이벤트 루프에 꽂을 수없는 애플리케이션 안에 통합하려는 경우 여기에있는 것이 올바른 아이디어입니다. – dano

관련 문제