def start(self): # Pub self.pub = yield from aiozmq.create_zmq_stream( zmq.PUB, bind="tcp://*:*", loop=self.loop ) # Server self.server, self.server_t = yield from aiozmq.create_zmq_connection( lambda: ServerProtocol(self.process_message, self.loop), zmq.ROUTER, bind="tcp://*:*", loop=self.loop ) self.server_t.transport.setsockopt(zmq.IDENTITY, self.node_id.encode('utf-8')) # Sub self.sub, _ = yield from aiozmq.create_zmq_connection( lambda: SubProtocol(self.process_event, self.loop), zmq.SUB, loop=self.loop ) yield from super(ZeroMQMedium, self).start()
def go(): router_closed = asyncio.Future(loop=loop) dealer_closed = asyncio.Future(loop=loop) router, _ = yield from aiozmq.create_zmq_connection( lambda: ZmqRouterProtocol(router_closed), zmq.ROUTER, bind='tcp://127.0.0.1:*', loop=loop) addr = next(iter(router.bindings())) dealer, _ = yield from aiozmq.create_zmq_connection( lambda: ZmqDealerProtocol(count, dealer_closed), zmq.DEALER, connect=addr, loop=loop) msg = b'func', b'\0' * 200 gc.collect() t1 = time.monotonic() dealer.write(msg) yield from dealer_closed t2 = time.monotonic() gc.collect() router.close() yield from router_closed return t2 - t1
def go(): router_closed = asyncio.Future() dealer_closed = asyncio.Future() router, _ = yield from aiozmq.create_zmq_connection( lambda: ZmqRouterProtocol(router_closed), zmq.ROUTER, bind='tcp://127.0.0.1:*') addr = list(router.bindings())[0] queue = asyncio.Queue() dealer, _ = yield from aiozmq.create_zmq_connection( lambda: ZmqDealerProtocol(queue, dealer_closed), zmq.DEALER, connect=addr) for i in range(10): msg = (b'data', b'ask', str(i).encode('utf-8')) dealer.write(msg) answer = yield from queue.get() print(answer) dealer.close() yield from dealer_closed router.close() yield from router_closed
def go(): router_closed = asyncio.Future(loop=loop) dealer_closed = asyncio.Future(loop=loop) router, _ = yield from aiozmq.create_zmq_connection( lambda: ZmqRouterProtocol(router_closed), zmq.ROUTER, bind='tcp://127.0.0.1:*', loop=loop) addr = next(iter(router.bindings())) dealer, _ = yield from aiozmq.create_zmq_connection( lambda: ZmqDealerProtocol(count, dealer_closed), zmq.DEALER, connect=addr, loop=loop) msg = b'func', b'\0'*200 gc.collect() t1 = time.monotonic() dealer.write(msg) yield from dealer_closed t2 = time.monotonic() gc.collect() router.close() yield from router_closed return t2 - t1
def connect_rpc(*, connect=None, bind=None, loop=None, error_table=None, translation_table=None, timeout=None): """A coroutine that creates and connects/binds RPC client. Usually for this function you need to use *connect* parameter, but ZeroMQ does not forbid to use *bind*. error_table -- an optional table for custom exception translators. timeout -- an optional timeout for RPC calls. If timeout is not None and remote call takes longer than timeout seconds then asyncio.TimeoutError will be raised at client side. If the server will return an answer after timeout has been raised that answer **is ignored**. translation_table -- an optional table for custom value translators. loop -- an optional parameter to point ZmqEventLoop instance. If loop is None then default event loop will be given by asyncio.get_event_loop call. Returns a RPCClient instance. """ if loop is None: loop = asyncio.get_event_loop() transp, proto = yield from create_zmq_connection( lambda: _ClientProtocol(loop, error_table=error_table, translation_table=translation_table), zmq.DEALER, connect=connect, bind=bind, loop=loop) return RPCClient(loop, proto, timeout=timeout)
def connect(): with self.assertRaises(OSError): yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.SUB, connect='badaddr', loop=self.loop)
def test_close_on_error(self): port = find_unused_port() tr1, pr1 = self.loop.run_until_complete( aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.REQ, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop)) handler = mock.Mock() self.loop.set_exception_handler(handler) sock = tr1.get_extra_info('zmq_socket') sock.close() tr1.write([b'data']) self.assertTrue(tr1._closing) handler.assert_called_with( self.loop, { 'protocol': pr1, 'exception': mock.ANY, 'transport': tr1, 'message': 'Fatal write error on zmq socket transport' }) # expecting 'Socket operation on non-socket' if sys.platform == 'darwin': errno = 38 else: errno = 88 check_errno(errno, handler.call_args[0][1]['exception'])
def test_close_on_error(self): port = find_unused_port() tr1, pr1 = self.loop.run_until_complete(aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.REQ, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop)) handler = mock.Mock() self.loop.set_exception_handler(handler) sock = tr1.get_extra_info('zmq_socket') sock.close() tr1.write([b'data']) self.assertTrue(tr1._closing) handler.assert_called_with( self.loop, {'protocol': pr1, 'exception': mock.ANY, 'transport': tr1, 'message': 'Fatal write error on zmq socket transport'}) # expecting 'Socket operation on non-socket' if sys.platform == 'darwin': errno = 38 else: errno = 88 check_errno(errno, handler.call_args[0][1]['exception'])
def start(self): self.logger.info("Creating Front Router...") self.front_router, _ = yield from aiozmq.create_zmq_connection( lambda: _FrontProtocol(self), zmq.ROUTER) front_endpoint = yield from self.front_router.bind("ipc://@/temp/front_router") self.front_router.setsockopt(zmq.IDENTITY, b"FRONT") self.logger.info("Front Router bind to %s" % front_endpoint) self.logger.info("Creating Forward Router...") self.forward_router, _ = yield from aiozmq.create_zmq_connection( lambda: _ForwardProtocol(self), zmq.ROUTER) self.forward_router.setsockopt(zmq.IDENTITY, b"FORWARD") # forward_connect = yield from self.forward_router.connect("ipc://@/temp/gateway") forward_connect = yield from self.forward_router.connect("tcp://127.0.0.1:8888") time.sleep(1) self.logger.info("Forward Router connect to %s" % forward_connect)
def go(): port = find_unused_port() server = yield from aiozmq.rpc.serve_rpc( MyHandler(self.loop), bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop) tr, pr = yield from create_zmq_connection( lambda: Protocol(self.loop), zmq.DEALER, connect='tcp://127.0.0.1:{}'.format(port), loop=self.loop) with log_hook('aiozmq.rpc', self.err_queue): tr.write([ struct.pack('=HHLd', 1, 2, 3, 4), msgpack.packb((1, 2)), b'bad_kwargs' ]) ret = yield from self.err_queue.get() self.assertEqual(logging.CRITICAL, ret.levelno) self.assertEqual("Cannot unpack %r", ret.msg) self.assertEqual( ([mock.ANY, mock.ANY, mock.ANY, b'bad_kwargs'], ), ret.args) self.assertIsNotNone(ret.exc_info) self.assertTrue(pr.received.empty()) server.close()
def test_close_on_error(self): port = find_unused_port() tr1, pr1 = self.loop.run_until_complete( aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.REQ, bind="tcp://127.0.0.1:{}".format(port), ) ) handler = mock.Mock() self.loop.set_exception_handler(handler) sock = tr1.get_extra_info("zmq_socket") sock.close() tr1.write([b"data"]) self.assertTrue(tr1._closing) handler.assert_called_with( self.loop, { "protocol": pr1, "exception": mock.ANY, "transport": tr1, "message": "Fatal write error on zmq socket transport", }, ) # expecting 'Socket operation on non-socket' if sys.platform == "darwin": errno = 38 else: errno = 88 check_errno(errno, handler.call_args[0][1]["exception"])
def connect_pipeline(*, connect=None, bind=None, loop=None, translation_table=None): """A coroutine that creates and connects/binds Pipeline client instance. Usually for this function you need to use *connect* parameter, but ZeroMQ does not forbid to use *bind*. translation_table -- an optional table for custom value translators. loop -- an optional parameter to point ZmqEventLoop instance. If loop is None then default event loop will be given by asyncio.get_event_loop() call. Returns PipelineClient instance. """ if loop is None: loop = asyncio.get_event_loop() transp, proto = yield from create_zmq_connection( lambda: _ClientProtocol(loop, translation_table=translation_table), zmq.PUSH, connect=connect, bind=bind, loop=loop) return PipelineClient(loop, proto)
def go(): port = find_unused_port() server = yield from aiozmq.rpc.serve_rpc( MyHandler(self.loop), bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop) tr, pr = yield from create_zmq_connection( lambda: Protocol(self.loop), zmq.DEALER, connect='tcp://127.0.0.1:{}'.format(port), loop=self.loop) with log_hook('aiozmq.rpc', self.err_queue): tr.write([struct.pack('=HHLd', 1, 2, 3, 4), msgpack.packb((1, 2)), b'bad_kwargs']) ret = yield from self.err_queue.get() self.assertEqual(logging.CRITICAL, ret.levelno) self.assertEqual("Cannot unpack %r", ret.msg) self.assertEqual( ([mock.ANY, mock.ANY, mock.ANY, b'bad_kwargs'],), ret.args) self.assertIsNotNone(ret.exc_info) self.assertTrue(pr.received.empty()) server.close()
def go(): port = find_unused_port() tr, pr = yield from create_zmq_connection( lambda: Protocol(self.loop), zmq.DEALER, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop) client = yield from aiozmq.rpc.connect_rpc( connect='tcp://127.0.0.1:{}'.format(port), loop=self.loop) with log_hook('aiozmq.rpc', self.err_queue): tr.write([struct.pack('=HHLd?', 1, 2, 3, 4, True), b'bad_answer']) ret = yield from self.err_queue.get() self.assertEqual(logging.CRITICAL, ret.levelno) self.assertEqual("Cannot unpack %r", ret.msg) self.assertEqual( ([mock.ANY, b'bad_answer'],), ret.args) self.assertIsNotNone(ret.exc_info) client.close() tr.close()
def connect(): with self.assertRaises(ValueError): yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.SUB, connect='tcp://example.com:5555', loop=self.loop)
def go(): port = find_unused_port() tr, pr = yield from create_zmq_connection( lambda: Protocol(self.loop), zmq.DEALER, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop) client = yield from aiozmq.rpc.connect_rpc( connect='tcp://127.0.0.1:{}'.format(port), loop=self.loop) with log_hook('aiozmq.rpc', self.err_queue): tr.write([ struct.pack('=HHLd?', 1, 2, 34435, 4, True), msgpack.packb((1, 2)) ]) ret = yield from self.err_queue.get() self.assertEqual(logging.CRITICAL, ret.levelno) self.assertEqual("Unknown answer id: %d (%d %d %f %d) -> %s", ret.msg) self.assertEqual((mock.ANY, 1, 2, 4.0, True, (1, 2)), ret.args) self.assertIsNone(ret.exc_info) client.close()
def go(): port = find_unused_port() tr, pr = yield from create_zmq_connection( lambda: Protocol(self.loop), zmq.DEALER, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop) client = yield from aiozmq.rpc.connect_rpc( connect='tcp://127.0.0.1:{}'.format(port), loop=self.loop) with log_hook('aiozmq.rpc', self.err_queue): tr.write([struct.pack('=HHLd?', 1, 2, 34435, 4, True), msgpack.packb((1, 2))]) ret = yield from self.err_queue.get() self.assertEqual(logging.CRITICAL, ret.levelno) self.assertEqual("Unknown answer id: %d (%d %d %f %d) -> %s", ret.msg) self.assertEqual( (mock.ANY, 1, 2, 4.0, True, (1, 2)), ret.args) self.assertIsNone(ret.exc_info) client.close()
def start(self): self.logger.info("Creating gateway Router...") self.gateway_router, _ = yield from aiozmq.create_zmq_connection( lambda: _GatewayProtocol(self), zmq.ROUTER) #gateway_connect = yield from self.gateway_router.bind("ipc://@/temp/gateway") self.gateway_router.setsockopt(zmq.IDENTITY, b"GATEWAY") gateway_connect = yield from self.gateway_router.bind("tcp://*:8888") self.logger.info("Gateway bind to %s " % gateway_connect)
def go(): # Create server and bind st, sp = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.ROUTER, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop) yield from sp.wait_ready addr = list(st.bindings())[0] # Create client but don't connect it yet. ct, cp = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.DEALER, loop=self.loop) yield from cp.wait_ready # Establish an event monitor on the client socket yield from ct.enable_monitor() # Now that the socket event monitor is established, connect # the client to the server which will generate some events. yield from ct.connect(addr) yield from asyncio.sleep(0.1, loop=self.loop) yield from ct.disconnect(addr) yield from asyncio.sleep(0.1, loop=self.loop) yield from ct.connect(addr) # Send a message to the server. The server should respond and # this is used to compete the wait_done future. ct.write([b'Hello']) yield from cp.wait_done yield from ct.disable_monitor() ct.close() yield from cp.wait_closed st.close() yield from sp.wait_closed # Confirm that the events received by the monitor were valid. self.assertGreater(cp.events_received.qsize(), 0) while not cp.events_received.empty(): event = yield from cp.events_received.get() self.assertIn(event.event, ZMQ_EVENTS)
def connect(): tr, pr = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.SUB, bind='tcp://127.0.0.1:*', loop=self.loop) yield from pr.connected return tr, pr
def connect(): tr, pr = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.SUB, connect='tcp://127.0.0.1:{}'.format(port), loop=self.loop) yield from pr.connected return tr, pr
def connect(): tr, pr = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.SUB, zmq_sock=zmq_sock, loop=self.loop) yield from pr.connected return tr, pr
def test_default_event_loop(self): asyncio.set_event_loop(self.loop) port = find_unused_port() tr1, pr1 = self.loop.run_until_complete(aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.REQ, bind='tcp://127.0.0.1:{}'.format(port))) self.assertIs(self.loop, tr1._loop) tr1.close()
def coro(): tr, pr = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.DEALER, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop) yield from pr.connected self.assertEqual(zmq.DEALER, tr.getsockopt(zmq.TYPE)) return tr, pr
def connect_rep(): tr2, pr2 = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.REP, connect='inproc://test', loop=self.loop) self.assertEqual('CONNECTED', pr2.state) yield from pr2.connected return tr2, pr2
def connect_req(): tr1, pr1 = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.REQ, bind='inproc://test', loop=self.loop) self.assertEqual('CONNECTED', pr1.state) yield from pr1.connected return tr1, pr1
def start(self, loop): router_closed = asyncio.Future() route_manager = self.router self.server, _ = yield from aiozmq.create_zmq_connection( lambda: ZmqRouterProtocol(router_closed, loop, route_manager), zmq.ROUTER, bind='tcp://' + self.host + ':' + self.port) return self.server
def coro(): tr, pr = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.DEALER, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop) yield from pr.connected self.assertEqual(zmq.DEALER, tr.get_extra_info('zmq_type')) tr.close()
def test_resume_reading_not_paused(self): port = find_unused_port() tr1, pr1 = self.loop.run_until_complete(aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.REQ, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop)) with self.assertRaises(RuntimeError): tr1.resume_reading() tr1.close()
def setup(self): factory1 = lambda: _CircusSubProtocol(self) factory2 = lambda: _CircusDealerProtocol(self, '_rep1') factory3 = lambda: _CircusDealerProtocol(self, '_rep2') self._sub, __ = yield from create_zmq_connection(factory1, SUB) self._req1, _ = yield from create_zmq_connection(factory2, DEALER) self._req2, _ = yield from create_zmq_connection(factory3, DEALER) self._sub.subscribe(b'') self._sub.connect(_CIRCUS_STATS_ADDR) self._req1.setsockopt(LINGER, 0) self._req1.setsockopt(IDENTITY, uuid4().hex.encode()) self._req1.connect(_CIRCUS_CONTROL_ADDR) self._req2.setsockopt(LINGER, 0) self._req2.setsockopt(IDENTITY, uuid4().hex.encode()) self._req2.connect(_CIRCUS_CONTROL_ADDR)
def pubsub_forwarding(host, port, translate=None, bind_address='0.0.0.0', server_port=0, *, loop=None): bind_address = socket.gethostbyname(bind_address) connect = 'tcp://{}:{}'.format(host, port) bind = 'tcp://{}:{}'.format(bind_address, server_port) handler = ForwardingHandler(translate) # Create subscriber _, subscriber = yield from aiozmq.create_zmq_connection( lambda: SubscriberProtocol(handler), zmq.SUB, connect=connect, loop=loop) handler.register_subscriber(subscriber) # Create publisher transport, publisher = yield from aiozmq.create_zmq_connection( lambda: PublisherProtocol(handler), zmq.XPUB, bind=bind, loop=loop) handler.register_publisher(publisher) # Return handler server_endpoint = list(transport.bindings())[0] bind_address, server_port = server_endpoint.split('/')[-1].split(':') return handler, bind_address, int(server_port)
def connect(): addr = 'tcp://localhost:{}'.format(port) tr, pr = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.SUB, connect=addr, loop=self.loop) yield from pr.connected self.assertEqual({addr}, tr.connections()) tr.close()
def make_pub_sub(self): port = find_unused_port() tr1, pr1 = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.PUB, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop) self.assertEqual('CONNECTED', pr1.state) yield from pr1.connected tr2, pr2 = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.SUB, connect='tcp://127.0.0.1:{}'.format(port), loop=self.loop) self.assertEqual('CONNECTED', pr2.state) yield from pr2.connected return tr1, pr1, tr2, pr2
def test_close_closing(self): port = find_unused_port() tr1, pr1 = self.loop.run_until_complete(aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.REQ, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop)) tr1.close() self.assertTrue(tr1._closing) tr1.close() self.assertTrue(tr1._closing)
def coro(): tr, pr = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.DEALER, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop) yield from pr.connected self.assertRegex( repr(tr), '<ZmqTransport sock=<[^>]+> ' 'type=DEALER read=idle write=<idle, bufsize=0>>') tr.close()
def serve_pubsub(handler, *, subscribe=None, connect=None, bind=None, loop=None, translation_table=None, log_exceptions=False, exclude_log_exceptions=(), timeout=None): """A coroutine that creates and connects/binds pubsub server instance. Usually for this function you need to use *bind* parameter, but ZeroMQ does not forbid to use *connect*. handler -- an object which processes incoming pipeline calls. Usually you like to pass AttrHandler instance. log_exceptions -- log exceptions from remote calls if True. subscribe -- subscription specification. Subscribe server to topics. Allowed parameters are str, bytes, iterable of str or bytes. translation_table -- an optional table for custom value translators. exclude_log_exceptions -- sequence of exception classes than should not be logged. timeout -- timeout for performing handling of async server calls. loop -- an optional parameter to point ZmqEventLoop. If loop is None then default event loop will be given by asyncio.get_event_loop() call. Returns PubSubService instance. Raises OSError on system error. Raises TypeError if arguments have inappropriate type. """ if loop is None: loop = asyncio.get_event_loop() transp, proto = yield from create_zmq_connection( lambda: _ServerProtocol(loop, handler, translation_table=translation_table, log_exceptions=log_exceptions, exclude_log_exceptions=exclude_log_exceptions, timeout=timeout), zmq.SUB, connect=connect, bind=bind, loop=loop) serv = PubSubService(loop, proto) if subscribe is not None: if isinstance(subscribe, (str, bytes)): subscribe = [subscribe] else: if not isinstance(subscribe, Iterable): raise TypeError('bind should be str, bytes or iterable') for topic in subscribe: serv.subscribe(topic) return serv
def go(): st, sp = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.ROUTER, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop) yield from sp.connected addr = list(st.bindings())[0] ct, cp = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.DEALER, connect=addr, loop=self.loop) yield from cp.connected ct.close() yield from cp.closed st.close() yield from sp.closed
def start(self): self.logger.info("Creating Sender REQ...") self.sender, _ = yield from aiozmq.create_zmq_connection( lambda: _SenderProtocol(self), zmq.REQ) self.sender.setsockopt(zmq.IDENTITY, b"SENDER") sender_connect = yield from self.sender.connect("ipc://@/temp/front_router") self.logger.info("Sender connect to %s" % sender_connect) time.sleep(1) send_message = [b'echo', b'req', b'hello'] self.sender.write(send_message) self.logger.info("Sender sent message %r" % send_message)
def go(): tr, pr = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.DEALER, loop=self.loop) yield from pr.connected yield from tr.enable_monitor() tr.abort() yield from pr.closed self.assertIsNone(tr._monitor)
def test_double_force_close(self): port = find_unused_port() tr1, pr1 = self.loop.run_until_complete(aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.REQ, bind='tcp://127.0.0.1:{}'.format(port), loop=self.loop)) handler = mock.Mock() self.loop.set_exception_handler(handler) err = RuntimeError('error') tr1._fatal_error(err) tr1._fatal_error(err) self.loop.run_until_complete(pr1.closed)
def go(): st, sp = yield from aiozmq.create_zmq_connection( Protocol, zmq.ROUTER, bind='tcp://127.0.0.1:*') yield from sp.wait_ready addr = list(st.bindings())[0] ct, cp = yield from aiozmq.create_zmq_connection( Protocol, zmq.DEALER, connect=addr) yield from cp.wait_ready # Enable the socket monitor on the client socket. Socket events # are passed to the 'event_received' method on the client protocol. yield from ct.enable_monitor() # Trigger some socket events while also sending a message to the # server. When the client protocol receives 4 response it will # fire the wait_done future. for i in range(4): yield from asyncio.sleep(0.1) yield from ct.disconnect(addr) yield from asyncio.sleep(0.1) yield from ct.connect(addr) yield from asyncio.sleep(0.1) ct.write([b'Hello']) yield from cp.wait_done # The socket monitor can be explicitly disabled if necessary. # yield from ct.disable_monitor() # If a socket monitor is left enabled on a socket being closed, # the socket monitor will be closed automatically. ct.close() yield from cp.wait_closed st.close() yield from sp.wait_closed
def go(): tr, pr = yield from aiozmq.create_zmq_connection( lambda: Protocol(self.loop), zmq.REQ, connect=[addr1, addr2], loop=self.loop) yield from pr.connected self.assertEqual({addr1, addr2}, tr.connections()) yield from tr.connect(addr3) self.assertEqual({addr1, addr3, addr2}, tr.connections()) yield from tr.disconnect(addr1) self.assertEqual({addr2, addr3}, tr.connections()) tr.close()