title: Handling keyboard interrupt in async zmq
body: <p>I'm making a ZeroMQ server in <code>pyzmq</code> using <code>asyncio</code>. I'm trying to gracefully handle stopping the server, but there's very little documentation on the async module and there doesn't seem to be a simple way to handle stopping the current poll/await. Stopping the loop in the <code>.stop</code> method doesn't do much and won't actually exit.</p>
  
  <pre><code>import zmq
  import zmq.asyncio
  import asyncio
  
  class ZMQHandler():
      def __init__(self):
          self.loop = zmq.asyncio.ZMQEventLoop()
          asyncio.set_event_loop(self.loop)
          self.context = zmq.asyncio.Context()
          self.socket = self.context.socket(zmq.DEALER)
          self.socket.bind('tcp://127.0.0.1:5000')
          self.socket.linger = -1
  
  
      def start(self):
          asyncio.ensure_future(self.listen())
          self.loop.run_forever()
  
      def stop(self):
          print('Stopping')
          self.loop.stop()
  
      async def listen(self):
          self.raw = await self.socket.recv()
          asyncio.ensure_future(self.listen())
  </code></pre>
  
  <p>Here's some example code that would start this:</p>
  
  <pre><code>daemon = ZMQHandler()
  
  def signal_handler(num, frame):
      daemon.stop()
  
  signal.signal(signal.SIGTERM, signal_handler)
  signal.signal(signal.SIGINT, signal_handler)
  
  daemon.start()
  </code></pre>
  
  <p>How do I gracefully stop this when it's running? When I call <code>self.socket.close()</code>, I get the error <code>zmq.error.ZMQError: Socket operation on non-socket</code>, and if I call <code>self.context.destroy()</code> it basically complains that the sockets weren't terminated cleanly with <code>ETERM</code>.</p>