|
|
import socket
|
|
|
|
|
|
import uuid
|
|
|
import zmq
|
|
|
|
|
|
from IPython.parallel.util import disambiguate_url
|
|
|
|
|
|
class EngineCommunicator(object):
|
|
|
|
|
|
def __init__(self, interface='tcp://*', identity=None):
|
|
|
self._ctx = zmq.Context()
|
|
|
self.socket = self._ctx.socket(zmq.XREP)
|
|
|
self.pub = self._ctx.socket(zmq.PUB)
|
|
|
self.sub = self._ctx.socket(zmq.SUB)
|
|
|
|
|
|
# configure sockets
|
|
|
self.identity = identity or bytes(uuid.uuid4())
|
|
|
print(self.identity)
|
|
|
self.socket.setsockopt(zmq.IDENTITY, self.identity)
|
|
|
self.sub.setsockopt(zmq.SUBSCRIBE, b'')
|
|
|
|
|
|
# bind to ports
|
|
|
port = self.socket.bind_to_random_port(interface)
|
|
|
pub_port = self.pub.bind_to_random_port(interface)
|
|
|
self.url = interface+":%i"%port
|
|
|
self.pub_url = interface+":%i"%pub_port
|
|
|
# guess first public IP from socket
|
|
|
self.location = socket.gethostbyname_ex(socket.gethostname())[-1][0]
|
|
|
self.peers = {}
|
|
|
|
|
|
def __del__(self):
|
|
|
self.socket.close()
|
|
|
self.pub.close()
|
|
|
self.sub.close()
|
|
|
self._ctx.term()
|
|
|
|
|
|
@property
|
|
|
def info(self):
|
|
|
"""return the connection info for this object's sockets."""
|
|
|
return (self.identity, self.url, self.pub_url, self.location)
|
|
|
|
|
|
def connect(self, peers):
|
|
|
"""connect to peers. `peers` will be a dict of 4-tuples, keyed by name.
|
|
|
{peer : (ident, addr, pub_addr, location)}
|
|
|
where peer is the name, ident is the XREP identity, addr,pub_addr are the
|
|
|
"""
|
|
|
for peer, (ident, url, pub_url, location) in peers.items():
|
|
|
self.peers[peer] = ident
|
|
|
if ident != self.identity:
|
|
|
self.sub.connect(disambiguate_url(pub_url, location))
|
|
|
if ident > self.identity:
|
|
|
# prevent duplicate xrep, by only connecting
|
|
|
# engines to engines with higher IDENTITY
|
|
|
# a doubly-connected pair will crash
|
|
|
self.socket.connect(disambiguate_url(url, location))
|
|
|
|
|
|
def send(self, peers, msg, flags=0, copy=True):
|
|
|
if not isinstance(peers, list):
|
|
|
peers = [peers]
|
|
|
if not isinstance(msg, list):
|
|
|
msg = [msg]
|
|
|
for p in peers:
|
|
|
ident = self.peers[p]
|
|
|
self.socket.send_multipart([ident]+msg, flags=flags, copy=copy)
|
|
|
|
|
|
def recv(self, flags=0, copy=True):
|
|
|
return self.socket.recv_multipart(flags=flags, copy=copy)[1:]
|
|
|
|
|
|
def publish(self, msg, flags=0, copy=True):
|
|
|
if not isinstance(msg, list):
|
|
|
msg = [msg]
|
|
|
self.pub.send_multipart(msg, copy=copy)
|
|
|
|
|
|
def consume(self, flags=0, copy=True):
|
|
|
return self.sub.recv_multipart(flags=flags, copy=copy)
|
|
|
|
|
|
|
|
|
|