diff --git a/examples/Calc.hs b/examples/Calc.hs
--- a/examples/Calc.hs
+++ b/examples/Calc.hs
@@ -213,7 +213,7 @@
   , displayResult = displayRes
   , displayOutput = displayOut
   , completion = langCompletion
-  , objectInfo = langInfo
+  , inspectInfo = langInfo
   , run = parseAndRun
   , debug = False
   }
diff --git a/ipython-kernel.cabal b/ipython-kernel.cabal
--- a/ipython-kernel.cabal
+++ b/ipython-kernel.cabal
@@ -1,5 +1,5 @@
 name:                ipython-kernel
-version:             0.6.1.0
+version:             0.6.1.1
 synopsis:            A library for creating kernels for IPython frontends
 
 description:         ipython-kernel is a library for communicating with frontends for the interactive IPython framework. It is used extensively in IHaskell, the interactive Haskell environment.
diff --git a/src/IHaskell/IPython/Message/UUID.hs b/src/IHaskell/IPython/Message/UUID.hs
--- a/src/IHaskell/IPython/Message/UUID.hs
+++ b/src/IHaskell/IPython/Message/UUID.hs
@@ -1,7 +1,7 @@
 -- | Description : UUID generator and data structure
 --
 -- Generate, parse, and pretty print UUIDs for use with IPython.
-module IHaskell.IPython.Message.UUID (UUID, random, randoms) where
+module IHaskell.IPython.Message.UUID (UUID, random, randoms, uuidToString) where
 
 import           Control.Monad (mzero, replicateM)
 import           Control.Applicative ((<$>))
@@ -16,7 +16,7 @@
      -- present in the correct locations. For the purposes of new UUIDs, it does not matter,
      -- but IPython expects UUIDs passed to kernels to be returned unchanged, so we cannot
      -- actually parse them.
-      UUID String
+      UUID { uuidToString :: String }
   deriving (Show, Read, Eq, Ord)
 
 -- | Generate a list of random UUIDs.
@@ -28,7 +28,7 @@
 random :: IO UUID
 random = UUID <$> show <$> nextRandom
 
--- Allows reading and writing UUIDs as Strings in JSON. 
+-- Allows reading and writing UUIDs as Strings in JSON.
 instance FromJSON UUID where
   parseJSON val@(String _) = UUID <$> parseJSON val
 
diff --git a/src/IHaskell/IPython/Types.hs b/src/IHaskell/IPython/Types.hs
--- a/src/IHaskell/IPython/Types.hs
+++ b/src/IHaskell/IPython/Types.hs
@@ -25,6 +25,7 @@
     HistoryAccessType(..),
     HistoryReplyElement(..),
     replyType,
+    showMessageType,
 
     -- ** IPython display data message
     DisplayData(..),
@@ -63,7 +64,7 @@
        Profile
          { ip :: IP                     -- ^ The IP on which to listen.
          , transport :: Transport       -- ^ The transport mechanism.
-         , stdinPort :: Port            -- ^ The stdin channel port. 
+         , stdinPort :: Port            -- ^ The stdin channel port.
          , controlPort :: Port          -- ^ The control channel port.
          , hbPort :: Port               -- ^ The heartbeat channel port.
          , shellPort :: Port            -- ^ The shell command port.
diff --git a/src/IHaskell/IPython/ZeroMQ.hs b/src/IHaskell/IPython/ZeroMQ.hs
--- a/src/IHaskell/IPython/ZeroMQ.hs
+++ b/src/IHaskell/IPython/ZeroMQ.hs
@@ -5,18 +5,28 @@
 -- The "ZeroMQ" module abstracts away the low-level 0MQ based interface with IPython, replacing it
 -- instead with a Haskell Channel based interface. The `serveProfile` function takes a IPython
 -- profile specification and returns the channel interface to use.
-module IHaskell.IPython.ZeroMQ (ZeroMQInterface(..), ZeroMQStdin(..), serveProfile, serveStdin) where
+module IHaskell.IPython.ZeroMQ (
+    ZeroMQInterface(..),
+    ZeroMQStdin(..),
+    serveProfile,
+    serveStdin,
+    ZeroMQEphemeralPorts,
+    withEphemeralPorts,
+    ) where
 
+import           Control.Concurrent
+import           Control.Exception
+import           Control.Monad
+import           Data.Aeson
 import qualified Data.ByteString.Lazy as LBS
 import           Data.ByteString (ByteString)
 import qualified Data.ByteString.Char8 as Char
-import           Control.Concurrent
-import           Control.Monad
-import           System.IO.Unsafe
-import           Data.Aeson (encode)
-import           System.ZMQ4 hiding (stdin)
+import           Data.Char
 import           Data.Digest.Pure.SHA as SHA
 import           Data.Monoid ((<>))
+import qualified Data.Text.Encoding as Text
+import           System.ZMQ4 as ZMQ4 hiding (stdin)
+import           Text.Read (readMaybe)
 
 import           IHaskell.IPython.Types
 import           IHaskell.IPython.Message.Parser
@@ -50,6 +60,23 @@
          , stdinReplyChannel :: Chan Message
          }
 
+-- | Create new channels for a ZeroMQInterface
+newZeroMQInterface :: ByteString -> IO ZeroMQInterface
+newZeroMQInterface key = do
+  shellReqChan <- newChan
+  shellRepChan <- newChan
+  controlReqChan <- dupChan shellReqChan
+  controlRepChan <- dupChan shellRepChan
+  iopubChan <- newChan
+  return $! Channels
+    { shellRequestChannel = shellReqChan
+    , shellReplyChannel = shellRepChan
+    , controlRequestChannel = controlReqChan
+    , controlReplyChannel = controlRepChan
+    , iopubChannel = iopubChan
+    , hmacKey = key
+    }
+
 -- | Start responding on all ZeroMQ channels used to communicate with IPython | via the provided
 -- profile. Return a set of channels which can be used to | communicate with IPython in a more
 -- structured manner.
@@ -57,14 +84,7 @@
              -> Bool               -- ^ Print debug output
              -> IO ZeroMQInterface -- ^ The Message-channel based interface to the sockets.
 serveProfile profile debug = do
-  -- Create all channels which will be used for higher level communication.
-  shellReqChan <- newChan
-  shellRepChan <- newChan
-  controlReqChan <- dupChan shellReqChan
-  controlRepChan <- dupChan shellRepChan
-  iopubChan <- newChan
-  let channels = Channels shellReqChan shellRepChan controlReqChan controlRepChan iopubChan
-                   (signatureKey profile)
+  channels <- newZeroMQInterface (signatureKey profile)
 
   -- Create the context in a separate thread that never finishes. If withContext or withSocket
   -- complete, the context or socket become invalid.
@@ -81,6 +101,81 @@
 
   return channels
 
+-- | Describes ports used when creating an ephemeral ZeroMQ session. Used to generate the ipython
+-- JSON config file.
+data ZeroMQEphemeralPorts =
+       ZeroMQEphemeralPorts
+         { ephHbPort :: !Port
+         , ephControlPort :: !Port
+         , ephShellPort :: !Port
+         , ephIOPubPort :: !Port
+         , ephSignatureKey :: !ByteString
+         }
+
+instance ToJSON ZeroMQEphemeralPorts where
+  toJSON ports =
+    object
+      [ "ip" .= ("127.0.0.1" :: String)
+      , "transport" .= TCP
+      , "control_port" .= ephControlPort ports
+      , "hb_port" .= ephHbPort ports
+      , "shell_port" .= ephShellPort ports
+      , "iopub_port" .= ephIOPubPort ports
+      , "key" .= Text.decodeUtf8 (ephSignatureKey ports)
+      ]
+
+parsePort :: String -> Maybe Int
+parsePort s = readMaybe num
+  where
+    num = reverse (takeWhile isNumber (reverse s))
+
+bindLocalEphemeralPort :: Socket a -> IO Int
+bindLocalEphemeralPort socket = do
+  bind socket $ "tcp://127.0.0.1:*"
+  endpointString <- lastEndpoint socket
+  case parsePort endpointString of
+    Nothing ->
+      fail $ "internalError: IHaskell.IPython.ZeroMQ.bindLocalEphemeralPort encountered a port index that could not be interpreted as an int."
+    Just endpointIndex ->
+      return endpointIndex
+
+-- | Run session for communicating with an IPython instance on ephemerally allocated ZMQ4 sockets.
+-- The sockets will be closed when the callback returns.
+withEphemeralPorts :: ByteString
+                   -> 
+                      -- ^ HMAC encryption key
+                      Bool
+                                           -> 
+                                              -- ^ Print debug output
+                                              (ZeroMQEphemeralPorts -> ZeroMQInterface -> IO a)
+                                                                  -> 
+                                                                     -- ^ Callback that takes the
+                                                                     -- interface to the sockets.
+                                                                     IO a
+withEphemeralPorts key debug callback = do
+  channels <- newZeroMQInterface key
+  -- Create the ZMQ4 context
+  withContext $ \context -> do
+    -- Create the sockets to communicate with.
+    withSocket context Rep $ \heartbeatSocket -> do
+      withSocket context Router $ \controlportSocket -> do
+        withSocket context Router $ \shellportSocket -> do
+          withSocket context Pub $ \iopubSocket -> do
+            -- Bind each socket to a local port, getting the port chosen.
+            hbPort <- bindLocalEphemeralPort heartbeatSocket
+            controlPort <- bindLocalEphemeralPort controlportSocket
+            shellPort <- bindLocalEphemeralPort shellportSocket
+            iopubPort <- bindLocalEphemeralPort iopubSocket
+            -- Create object to store ephemeral ports
+            let ports = ZeroMQEphemeralPorts { ephHbPort = hbPort, ephControlPort = controlPort, ephShellPort = shellPort, ephIOPubPort = iopubPort, ephSignatureKey = key }
+            -- Launch actions to listen to communicate between channels and cockets.
+            _ <- forkIO $ forever $ heartbeat channels heartbeatSocket
+            _ <- forkIO $ forever $ control debug channels controlportSocket
+            _ <- forkIO $ forever $ shell debug channels shellportSocket
+            _ <- forkIO $ checkedIOpub debug channels iopubSocket
+            -- Run callback function; provide it with both ports and channels.
+            callback ports channels
+
 serveStdin :: Profile -> IO ZeroMQStdin
 serveStdin profile = do
   reqChannel <- newChan
@@ -151,6 +246,27 @@
 iopub :: Bool -> ZeroMQInterface -> Socket Pub -> IO ()
 iopub debug channels socket =
   readChan (iopubChannel channels) >>= sendMessage debug (hmacKey channels) socket
+
+-- | Attempt to send a message along the socket, returning true if successful.
+trySendMessage :: Sender a => String -> Bool -> ByteString -> Socket a -> Message -> IO Bool
+trySendMessage nm debug hmacKey socket message = do
+  let zmqErrorHandler :: ZMQError -> IO Bool
+      zmqErrorHandler e
+        -- Ignore errors if we cannot send. We may want to forward this to the thread that tried put the
+        -- message in the Chan initially.
+        | errno e == 38 = return False
+        | otherwise = throwIO e
+  (sendMessage debug hmacKey socket message >> return True) `catch` zmqErrorHandler
+
+-- | Send messages via the iopub channel. This reads messages from the ZeroMQ iopub interface
+-- channel and then writes the messages to the socket. This is a checked implementation which will
+-- stop if the socket is closed.
+checkedIOpub :: Bool -> ZeroMQInterface -> Socket Pub -> IO ()
+checkedIOpub debug channels socket = do
+  msg <- readChan (iopubChannel channels)
+  cont <- trySendMessage "io" debug (hmacKey channels) socket msg
+  when cont $
+    checkedIOpub debug channels socket
 
 -- | Receive and parse a message from a socket.
 receiveMessage :: Receiver a => Bool -> Socket a -> IO Message
