1b2732e9dSimarom# coding: utf-8
2b2732e9dSimarom"""0MQ Socket pure Python methods."""
3b2732e9dSimarom
4b2732e9dSimarom# Copyright (C) PyZMQ Developers
5b2732e9dSimarom# Distributed under the terms of the Modified BSD License.
6b2732e9dSimarom
7b2732e9dSimarom
8b2732e9dSimaromimport codecs
9b2732e9dSimaromimport random
10b2732e9dSimaromimport warnings
11b2732e9dSimarom
12b2732e9dSimaromimport zmq
13b2732e9dSimaromfrom zmq.backend import Socket as SocketBase
14b2732e9dSimaromfrom .poll import Poller
15b2732e9dSimaromfrom . import constants
16b2732e9dSimaromfrom .attrsettr import AttributeSetter
17b2732e9dSimaromfrom zmq.error import ZMQError, ZMQBindError
18b2732e9dSimaromfrom zmq.utils import jsonapi
19b2732e9dSimaromfrom zmq.utils.strtypes import bytes,unicode,basestring
20b2732e9dSimaromfrom zmq.utils.interop import cast_int_addr
21b2732e9dSimarom
22b2732e9dSimaromfrom .constants import (
23b2732e9dSimarom    SNDMORE, ENOTSUP, POLLIN,
24b2732e9dSimarom    int64_sockopt_names,
25b2732e9dSimarom    int_sockopt_names,
26b2732e9dSimarom    bytes_sockopt_names,
27b2732e9dSimarom    fd_sockopt_names,
28b2732e9dSimarom)
29b2732e9dSimaromtry:
30b2732e9dSimarom    import cPickle
31b2732e9dSimarom    pickle = cPickle
32b2732e9dSimaromexcept:
33b2732e9dSimarom    cPickle = None
34b2732e9dSimarom    import pickle
35b2732e9dSimarom
36b2732e9dSimaromtry:
37b2732e9dSimarom    DEFAULT_PROTOCOL = pickle.DEFAULT_PROTOCOL
38b2732e9dSimaromexcept AttributeError:
39b2732e9dSimarom    DEFAULT_PROTOCOL = pickle.HIGHEST_PROTOCOL
40b2732e9dSimarom
41b2732e9dSimarom
42b2732e9dSimaromclass Socket(SocketBase, AttributeSetter):
43b2732e9dSimarom    """The ZMQ socket object
44b2732e9dSimarom
45b2732e9dSimarom    To create a Socket, first create a Context::
46b2732e9dSimarom
47b2732e9dSimarom        ctx = zmq.Context.instance()
48b2732e9dSimarom
49b2732e9dSimarom    then call ``ctx.socket(socket_type)``::
50b2732e9dSimarom
51b2732e9dSimarom        s = ctx.socket(zmq.ROUTER)
52b2732e9dSimarom
53b2732e9dSimarom    """
54b2732e9dSimarom    _shadow = False
55b2732e9dSimarom
56b2732e9dSimarom    def __del__(self):
57b2732e9dSimarom        if not self._shadow:
58b2732e9dSimarom            self.close()
59b2732e9dSimarom
60b2732e9dSimarom    # socket as context manager:
61b2732e9dSimarom    def __enter__(self):
62b2732e9dSimarom        """Sockets are context managers
63b2732e9dSimarom
64b2732e9dSimarom        .. versionadded:: 14.4
65b2732e9dSimarom        """
66b2732e9dSimarom        return self
67b2732e9dSimarom
68b2732e9dSimarom    def __exit__(self, *args, **kwargs):
69b2732e9dSimarom        self.close()
70b2732e9dSimarom
71b2732e9dSimarom    #-------------------------------------------------------------------------
72b2732e9dSimarom    # Socket creation
73b2732e9dSimarom    #-------------------------------------------------------------------------
74b2732e9dSimarom
75b2732e9dSimarom    @classmethod
76b2732e9dSimarom    def shadow(cls, address):
77b2732e9dSimarom        """Shadow an existing libzmq socket
78b2732e9dSimarom
79b2732e9dSimarom        address is the integer address of the libzmq socket
80b2732e9dSimarom        or an FFI pointer to it.
81b2732e9dSimarom
82b2732e9dSimarom        .. versionadded:: 14.1
83b2732e9dSimarom        """
84b2732e9dSimarom        address = cast_int_addr(address)
85b2732e9dSimarom        return cls(shadow=address)
86b2732e9dSimarom
87b2732e9dSimarom    #-------------------------------------------------------------------------
88b2732e9dSimarom    # Deprecated aliases
89b2732e9dSimarom    #-------------------------------------------------------------------------
90b2732e9dSimarom
91b2732e9dSimarom    @property
92b2732e9dSimarom    def socket_type(self):
93b2732e9dSimarom        warnings.warn("Socket.socket_type is deprecated, use Socket.type",
94b2732e9dSimarom            DeprecationWarning
95b2732e9dSimarom        )
96b2732e9dSimarom        return self.type
97b2732e9dSimarom
98b2732e9dSimarom    #-------------------------------------------------------------------------
99b2732e9dSimarom    # Hooks for sockopt completion
100b2732e9dSimarom    #-------------------------------------------------------------------------
101b2732e9dSimarom
102b2732e9dSimarom    def __dir__(self):
103b2732e9dSimarom        keys = dir(self.__class__)
104b2732e9dSimarom        for collection in (
105b2732e9dSimarom            bytes_sockopt_names,
106b2732e9dSimarom            int_sockopt_names,
107b2732e9dSimarom            int64_sockopt_names,
108b2732e9dSimarom            fd_sockopt_names,
109b2732e9dSimarom        ):
110b2732e9dSimarom            keys.extend(collection)
111b2732e9dSimarom        return keys
112b2732e9dSimarom
113b2732e9dSimarom    #-------------------------------------------------------------------------
114b2732e9dSimarom    # Getting/Setting options
115b2732e9dSimarom    #-------------------------------------------------------------------------
116b2732e9dSimarom    setsockopt = SocketBase.set
117b2732e9dSimarom    getsockopt = SocketBase.get
118b2732e9dSimarom
119b2732e9dSimarom    def set_string(self, option, optval, encoding='utf-8'):
120b2732e9dSimarom        """set socket options with a unicode object
121b2732e9dSimarom
122b2732e9dSimarom        This is simply a wrapper for setsockopt to protect from encoding ambiguity.
123b2732e9dSimarom
124b2732e9dSimarom        See the 0MQ documentation for details on specific options.
125b2732e9dSimarom
126b2732e9dSimarom        Parameters
127b2732e9dSimarom        ----------
128b2732e9dSimarom        option : int
129b2732e9dSimarom            The name of the option to set. Can be any of: SUBSCRIBE,
130b2732e9dSimarom            UNSUBSCRIBE, IDENTITY
131b2732e9dSimarom        optval : unicode string (unicode on py2, str on py3)
132b2732e9dSimarom            The value of the option to set.
133b2732e9dSimarom        encoding : str
134b2732e9dSimarom            The encoding to be used, default is utf8
135b2732e9dSimarom        """
136b2732e9dSimarom        if not isinstance(optval, unicode):
137b2732e9dSimarom            raise TypeError("unicode strings only")
138b2732e9dSimarom        return self.set(option, optval.encode(encoding))
139b2732e9dSimarom
140b2732e9dSimarom    setsockopt_unicode = setsockopt_string = set_string
141b2732e9dSimarom
142b2732e9dSimarom    def get_string(self, option, encoding='utf-8'):
143b2732e9dSimarom        """get the value of a socket option
144b2732e9dSimarom
145b2732e9dSimarom        See the 0MQ documentation for details on specific options.
146b2732e9dSimarom
147b2732e9dSimarom        Parameters
148b2732e9dSimarom        ----------
149b2732e9dSimarom        option : int
150b2732e9dSimarom            The option to retrieve.
151b2732e9dSimarom
152b2732e9dSimarom        Returns
153b2732e9dSimarom        -------
154b2732e9dSimarom        optval : unicode string (unicode on py2, str on py3)
155b2732e9dSimarom            The value of the option as a unicode string.
156b2732e9dSimarom        """
157b2732e9dSimarom
158b2732e9dSimarom        if option not in constants.bytes_sockopts:
159b2732e9dSimarom            raise TypeError("option %i will not return a string to be decoded"%option)
160b2732e9dSimarom        return self.getsockopt(option).decode(encoding)
161b2732e9dSimarom
162b2732e9dSimarom    getsockopt_unicode = getsockopt_string = get_string
163b2732e9dSimarom
164b2732e9dSimarom    def bind_to_random_port(self, addr, min_port=49152, max_port=65536, max_tries=100):
165b2732e9dSimarom        """bind this socket to a random port in a range
166b2732e9dSimarom
167b2732e9dSimarom        Parameters
168b2732e9dSimarom        ----------
169b2732e9dSimarom        addr : str
170b2732e9dSimarom            The address string without the port to pass to ``Socket.bind()``.
171b2732e9dSimarom        min_port : int, optional
172b2732e9dSimarom            The minimum port in the range of ports to try (inclusive).
173b2732e9dSimarom        max_port : int, optional
174b2732e9dSimarom            The maximum port in the range of ports to try (exclusive).
175b2732e9dSimarom        max_tries : int, optional
176b2732e9dSimarom            The maximum number of bind attempts to make.
177b2732e9dSimarom
178b2732e9dSimarom        Returns
179b2732e9dSimarom        -------
180b2732e9dSimarom        port : int
181b2732e9dSimarom            The port the socket was bound to.
182b2732e9dSimarom
183b2732e9dSimarom        Raises
184b2732e9dSimarom        ------
185b2732e9dSimarom        ZMQBindError
186b2732e9dSimarom            if `max_tries` reached before successful bind
187b2732e9dSimarom        """
188b2732e9dSimarom        for i in range(max_tries):
189b2732e9dSimarom            try:
190b2732e9dSimarom                port = random.randrange(min_port, max_port)
191b2732e9dSimarom                self.bind('%s:%s' % (addr, port))
192b2732e9dSimarom            except ZMQError as exception:
193b2732e9dSimarom                if not exception.errno == zmq.EADDRINUSE:
194b2732e9dSimarom                    raise
195b2732e9dSimarom            else:
196b2732e9dSimarom                return port
197b2732e9dSimarom        raise ZMQBindError("Could not bind socket to random port.")
198b2732e9dSimarom
199b2732e9dSimarom    def get_hwm(self):
200b2732e9dSimarom        """get the High Water Mark
201b2732e9dSimarom
202b2732e9dSimarom        On libzmq ≥ 3, this gets SNDHWM if available, otherwise RCVHWM
203b2732e9dSimarom        """
204b2732e9dSimarom        major = zmq.zmq_version_info()[0]
205b2732e9dSimarom        if major >= 3:
206b2732e9dSimarom            # return sndhwm, fallback on rcvhwm
207b2732e9dSimarom            try:
208b2732e9dSimarom                return self.getsockopt(zmq.SNDHWM)
209b2732e9dSimarom            except zmq.ZMQError as e:
210b2732e9dSimarom                pass
211b2732e9dSimarom
212b2732e9dSimarom            return self.getsockopt(zmq.RCVHWM)
213b2732e9dSimarom        else:
214b2732e9dSimarom            return self.getsockopt(zmq.HWM)
215b2732e9dSimarom
216b2732e9dSimarom    def set_hwm(self, value):
217b2732e9dSimarom        """set the High Water Mark
218b2732e9dSimarom
219b2732e9dSimarom        On libzmq ≥ 3, this sets both SNDHWM and RCVHWM
220b2732e9dSimarom        """
221b2732e9dSimarom        major = zmq.zmq_version_info()[0]
222b2732e9dSimarom        if major >= 3:
223b2732e9dSimarom            raised = None
224b2732e9dSimarom            try:
225b2732e9dSimarom                self.sndhwm = value
226b2732e9dSimarom            except Exception as e:
227b2732e9dSimarom                raised = e
228b2732e9dSimarom            try:
229b2732e9dSimarom                self.rcvhwm = value
230b2732e9dSimarom            except Exception:
231b2732e9dSimarom                raised = e
232b2732e9dSimarom
233b2732e9dSimarom            if raised:
234b2732e9dSimarom                raise raised
235b2732e9dSimarom        else:
236b2732e9dSimarom            return self.setsockopt(zmq.HWM, value)
237b2732e9dSimarom
238b2732e9dSimarom    hwm = property(get_hwm, set_hwm,
239b2732e9dSimarom        """property for High Water Mark
240b2732e9dSimarom
241b2732e9dSimarom        Setting hwm sets both SNDHWM and RCVHWM as appropriate.
242b2732e9dSimarom        It gets SNDHWM if available, otherwise RCVHWM.
243b2732e9dSimarom        """
244b2732e9dSimarom    )
245b2732e9dSimarom
246b2732e9dSimarom    #-------------------------------------------------------------------------
247b2732e9dSimarom    # Sending and receiving messages
248b2732e9dSimarom    #-------------------------------------------------------------------------
249b2732e9dSimarom
250b2732e9dSimarom    def send_multipart(self, msg_parts, flags=0, copy=True, track=False):
251b2732e9dSimarom        """send a sequence of buffers as a multipart message
252b2732e9dSimarom
253b2732e9dSimarom        The zmq.SNDMORE flag is added to all msg parts before the last.
254b2732e9dSimarom
255b2732e9dSimarom        Parameters
256b2732e9dSimarom        ----------
257b2732e9dSimarom        msg_parts : iterable
258b2732e9dSimarom            A sequence of objects to send as a multipart message. Each element
259b2732e9dSimarom            can be any sendable object (Frame, bytes, buffer-providers)
260b2732e9dSimarom        flags : int, optional
261b2732e9dSimarom            SNDMORE is handled automatically for frames before the last.
262b2732e9dSimarom        copy : bool, optional
263b2732e9dSimarom            Should the frame(s) be sent in a copying or non-copying manner.
264b2732e9dSimarom        track : bool, optional
265b2732e9dSimarom            Should the frame(s) be tracked for notification that ZMQ has
266b2732e9dSimarom            finished with it (ignored if copy=True).
267b2732e9dSimarom
268b2732e9dSimarom        Returns
269b2732e9dSimarom        -------
270b2732e9dSimarom        None : if copy or not track
271b2732e9dSimarom        MessageTracker : if track and not copy
272b2732e9dSimarom            a MessageTracker object, whose `pending` property will
273b2732e9dSimarom            be True until the last send is completed.
274b2732e9dSimarom        """
275b2732e9dSimarom        for msg in msg_parts[:-1]:
276b2732e9dSimarom            self.send(msg, SNDMORE|flags, copy=copy, track=track)
277b2732e9dSimarom        # Send the last part without the extra SNDMORE flag.
278b2732e9dSimarom        return self.send(msg_parts[-1], flags, copy=copy, track=track)
279b2732e9dSimarom
280b2732e9dSimarom    def recv_multipart(self, flags=0, copy=True, track=False):
281b2732e9dSimarom        """receive a multipart message as a list of bytes or Frame objects
282b2732e9dSimarom
283b2732e9dSimarom        Parameters
284b2732e9dSimarom        ----------
285b2732e9dSimarom        flags : int, optional
286b2732e9dSimarom            Any supported flag: NOBLOCK. If NOBLOCK is set, this method
287b2732e9dSimarom            will raise a ZMQError with EAGAIN if a message is not ready.
288b2732e9dSimarom            If NOBLOCK is not set, then this method will block until a
289b2732e9dSimarom            message arrives.
290b2732e9dSimarom        copy : bool, optional
291b2732e9dSimarom            Should the message frame(s) be received in a copying or non-copying manner?
292b2732e9dSimarom            If False a Frame object is returned for each part, if True a copy of
293b2732e9dSimarom            the bytes is made for each frame.
294b2732e9dSimarom        track : bool, optional
295b2732e9dSimarom            Should the message frame(s) be tracked for notification that ZMQ has
296b2732e9dSimarom            finished with it? (ignored if copy=True)
297b2732e9dSimarom
298b2732e9dSimarom        Returns
299b2732e9dSimarom        -------
300b2732e9dSimarom        msg_parts : list
301b2732e9dSimarom            A list of frames in the multipart message; either Frames or bytes,
302b2732e9dSimarom            depending on `copy`.
303b2732e9dSimarom
304b2732e9dSimarom        """
305b2732e9dSimarom        parts = [self.recv(flags, copy=copy, track=track)]
306b2732e9dSimarom        # have first part already, only loop while more to receive
307b2732e9dSimarom        while self.getsockopt(zmq.RCVMORE):
308b2732e9dSimarom            part = self.recv(flags, copy=copy, track=track)
309b2732e9dSimarom            parts.append(part)
310b2732e9dSimarom
311b2732e9dSimarom        return parts
312b2732e9dSimarom
313b2732e9dSimarom    def send_string(self, u, flags=0, copy=True, encoding='utf-8'):
314b2732e9dSimarom        """send a Python unicode string as a message with an encoding
315b2732e9dSimarom
316b2732e9dSimarom        0MQ communicates with raw bytes, so you must encode/decode
317b2732e9dSimarom        text (unicode on py2, str on py3) around 0MQ.
318b2732e9dSimarom
319b2732e9dSimarom        Parameters
320b2732e9dSimarom        ----------
321b2732e9dSimarom        u : Python unicode string (unicode on py2, str on py3)
322b2732e9dSimarom            The unicode string to send.
323b2732e9dSimarom        flags : int, optional
324b2732e9dSimarom            Any valid send flag.
325b2732e9dSimarom        encoding : str [default: 'utf-8']
326b2732e9dSimarom            The encoding to be used
327b2732e9dSimarom        """
328b2732e9dSimarom        if not isinstance(u, basestring):
329b2732e9dSimarom            raise TypeError("unicode/str objects only")
330b2732e9dSimarom        return self.send(u.encode(encoding), flags=flags, copy=copy)
331b2732e9dSimarom
332b2732e9dSimarom    send_unicode = send_string
333b2732e9dSimarom
334b2732e9dSimarom    def recv_string(self, flags=0, encoding='utf-8'):
335b2732e9dSimarom        """receive a unicode string, as sent by send_string
336b2732e9dSimarom
337b2732e9dSimarom        Parameters
338b2732e9dSimarom        ----------
339b2732e9dSimarom        flags : int
340b2732e9dSimarom            Any valid recv flag.
341b2732e9dSimarom        encoding : str [default: 'utf-8']
342b2732e9dSimarom            The encoding to be used
343b2732e9dSimarom
344b2732e9dSimarom        Returns
345b2732e9dSimarom        -------
346b2732e9dSimarom        s : unicode string (unicode on py2, str on py3)
347b2732e9dSimarom            The Python unicode string that arrives as encoded bytes.
348b2732e9dSimarom        """
349b2732e9dSimarom        b = self.recv(flags=flags)
350b2732e9dSimarom        return b.decode(encoding)
351b2732e9dSimarom
352b2732e9dSimarom    recv_unicode = recv_string
353b2732e9dSimarom
354b2732e9dSimarom    def send_pyobj(self, obj, flags=0, protocol=DEFAULT_PROTOCOL):
355b2732e9dSimarom        """send a Python object as a message using pickle to serialize
356b2732e9dSimarom
357b2732e9dSimarom        Parameters
358b2732e9dSimarom        ----------
359b2732e9dSimarom        obj : Python object
360b2732e9dSimarom            The Python object to send.
361b2732e9dSimarom        flags : int
362b2732e9dSimarom            Any valid send flag.
363b2732e9dSimarom        protocol : int
364b2732e9dSimarom            The pickle protocol number to use. The default is pickle.DEFAULT_PROTOCOl
365b2732e9dSimarom            where defined, and pickle.HIGHEST_PROTOCOL elsewhere.
366b2732e9dSimarom        """
367b2732e9dSimarom        msg = pickle.dumps(obj, protocol)
368b2732e9dSimarom        return self.send(msg, flags)
369b2732e9dSimarom
370b2732e9dSimarom    def recv_pyobj(self, flags=0):
371b2732e9dSimarom        """receive a Python object as a message using pickle to serialize
372b2732e9dSimarom
373b2732e9dSimarom        Parameters
374b2732e9dSimarom        ----------
375b2732e9dSimarom        flags : int
376b2732e9dSimarom            Any valid recv flag.
377b2732e9dSimarom
378b2732e9dSimarom        Returns
379b2732e9dSimarom        -------
380b2732e9dSimarom        obj : Python object
381b2732e9dSimarom            The Python object that arrives as a message.
382b2732e9dSimarom        """
383b2732e9dSimarom        s = self.recv(flags)
384b2732e9dSimarom        return pickle.loads(s)
385b2732e9dSimarom
386b2732e9dSimarom    def send_json(self, obj, flags=0, **kwargs):
387b2732e9dSimarom        """send a Python object as a message using json to serialize
388b2732e9dSimarom
389b2732e9dSimarom        Keyword arguments are passed on to json.dumps
390b2732e9dSimarom
391b2732e9dSimarom        Parameters
392b2732e9dSimarom        ----------
393b2732e9dSimarom        obj : Python object
394b2732e9dSimarom            The Python object to send
395b2732e9dSimarom        flags : int
396b2732e9dSimarom            Any valid send flag
397b2732e9dSimarom        """
398b2732e9dSimarom        msg = jsonapi.dumps(obj, **kwargs)
399b2732e9dSimarom        return self.send(msg, flags)
400b2732e9dSimarom
401b2732e9dSimarom    def recv_json(self, flags=0, **kwargs):
402b2732e9dSimarom        """receive a Python object as a message using json to serialize
403b2732e9dSimarom
404b2732e9dSimarom        Keyword arguments are passed on to json.loads
405b2732e9dSimarom
406b2732e9dSimarom        Parameters
407b2732e9dSimarom        ----------
408b2732e9dSimarom        flags : int
409b2732e9dSimarom            Any valid recv flag.
410b2732e9dSimarom
411b2732e9dSimarom        Returns
412b2732e9dSimarom        -------
413b2732e9dSimarom        obj : Python object
414b2732e9dSimarom            The Python object that arrives as a message.
415b2732e9dSimarom        """
416b2732e9dSimarom        msg = self.recv(flags)
417b2732e9dSimarom        return jsonapi.loads(msg, **kwargs)
418b2732e9dSimarom
419b2732e9dSimarom    _poller_class = Poller
420b2732e9dSimarom
421b2732e9dSimarom    def poll(self, timeout=None, flags=POLLIN):
422b2732e9dSimarom        """poll the socket for events
423b2732e9dSimarom
424b2732e9dSimarom        The default is to poll forever for incoming
425b2732e9dSimarom        events.  Timeout is in milliseconds, if specified.
426b2732e9dSimarom
427b2732e9dSimarom        Parameters
428b2732e9dSimarom        ----------
429b2732e9dSimarom        timeout : int [default: None]
430b2732e9dSimarom            The timeout (in milliseconds) to wait for an event. If unspecified
431b2732e9dSimarom            (or specified None), will wait forever for an event.
432b2732e9dSimarom        flags : bitfield (int) [default: POLLIN]
433b2732e9dSimarom            The event flags to poll for (any combination of POLLIN|POLLOUT).
434b2732e9dSimarom            The default is to check for incoming events (POLLIN).
435b2732e9dSimarom
436b2732e9dSimarom        Returns
437b2732e9dSimarom        -------
438b2732e9dSimarom        events : bitfield (int)
439b2732e9dSimarom            The events that are ready and waiting.  Will be 0 if no events were ready
440b2732e9dSimarom            by the time timeout was reached.
441b2732e9dSimarom        """
442b2732e9dSimarom
443b2732e9dSimarom        if self.closed:
444b2732e9dSimarom            raise ZMQError(ENOTSUP)
445b2732e9dSimarom
446b2732e9dSimarom        p = self._poller_class()
447b2732e9dSimarom        p.register(self, flags)
448b2732e9dSimarom        evts = dict(p.poll(timeout))
449b2732e9dSimarom        # return 0 if no events, otherwise return event bitfield
450b2732e9dSimarom        return evts.get(self, 0)
451b2732e9dSimarom
452b2732e9dSimarom    def get_monitor_socket(self, events=None, addr=None):
453b2732e9dSimarom        """Return a connected PAIR socket ready to receive the event notifications.
454b2732e9dSimarom
455b2732e9dSimarom        .. versionadded:: libzmq-4.0
456b2732e9dSimarom        .. versionadded:: 14.0
457b2732e9dSimarom
458b2732e9dSimarom        Parameters
459b2732e9dSimarom        ----------
460b2732e9dSimarom        events : bitfield (int) [default: ZMQ_EVENTS_ALL]
461b2732e9dSimarom            The bitmask defining which events are wanted.
462b2732e9dSimarom        addr :  string [default: None]
463b2732e9dSimarom            The optional endpoint for the monitoring sockets.
464b2732e9dSimarom
465b2732e9dSimarom        Returns
466b2732e9dSimarom        -------
467b2732e9dSimarom        socket :  (PAIR)
468b2732e9dSimarom            The socket is already connected and ready to receive messages.
469b2732e9dSimarom        """
470b2732e9dSimarom        # safe-guard, method only available on libzmq >= 4
471b2732e9dSimarom        if zmq.zmq_version_info() < (4,):
472b2732e9dSimarom            raise NotImplementedError("get_monitor_socket requires libzmq >= 4, have %s" % zmq.zmq_version())
473b2732e9dSimarom        if addr is None:
474b2732e9dSimarom            # create endpoint name from internal fd
475b2732e9dSimarom            addr = "inproc://monitor.s-%d" % self.FD
476b2732e9dSimarom        if events is None:
477b2732e9dSimarom            # use all events
478b2732e9dSimarom            events = zmq.EVENT_ALL
479b2732e9dSimarom        # attach monitoring socket
480b2732e9dSimarom        self.monitor(addr, events)
481b2732e9dSimarom        # create new PAIR socket and connect it
482b2732e9dSimarom        ret = self.context.socket(zmq.PAIR)
483b2732e9dSimarom        ret.connect(addr)
484b2732e9dSimarom        return ret
485b2732e9dSimarom
486b2732e9dSimarom    def disable_monitor(self):
487b2732e9dSimarom        """Shutdown the PAIR socket (created using get_monitor_socket)
488b2732e9dSimarom        that is serving socket events.
489b2732e9dSimarom
490b2732e9dSimarom        .. versionadded:: 14.4
491b2732e9dSimarom        """
492b2732e9dSimarom        self.monitor(None, 0)
493b2732e9dSimarom
494b2732e9dSimarom
495b2732e9dSimarom__all__ = ['Socket']
496