diff --git a/Network/Run/Core.hs b/Network/Run/Core.hs
new file mode 100644
--- /dev/null
+++ b/Network/Run/Core.hs
@@ -0,0 +1,48 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE CPP #-}
+
+module Network.Run.Core (
+    runClient
+  , resolve
+  , openServerSocket
+  ) where
+
+import qualified Control.Exception as E
+import Control.Monad (when)
+import Network.Socket
+
+runClient :: SocketType -> String -> String -> (Socket -> SockAddr -> IO a) -> IO a
+runClient socketType host port client = withSocketsDo $ do
+    addr <- resolve socketType (Just host) port False
+    let sockAddr = addrAddress addr
+#if MIN_VERSION_network(3,1,1)
+    E.bracket (open addr) (\sock -> gracefulClose sock 5000)
+                          (\sock -> client sock sockAddr)
+#else
+    E.bracket (open addr) close $ \sock -> client sock sockAddr
+#endif
+  where
+    open addr = do
+        sock <- openSocket addr
+        when (socketType == Stream) $ connect sock $ addrAddress addr
+        return sock
+
+resolve :: SocketType -> Maybe HostName -> ServiceName -> Bool -> IO AddrInfo
+resolve socketType mhost port passive =
+        head <$> getAddrInfo (Just hints) mhost (Just port)
+  where
+    hints = defaultHints {
+        addrSocketType = socketType
+      , addrFlags = if passive then [AI_PASSIVE] else []
+      }
+
+openSocket :: AddrInfo -> IO Socket
+openSocket addr = socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
+
+openServerSocket :: AddrInfo -> IO Socket
+openServerSocket addr = do
+    sock <- openSocket addr
+    setSocketOption sock ReuseAddr 1
+    withFdSocket sock $ setCloseOnExecIfNeeded
+    bind sock $ addrAddress addr
+    return sock
diff --git a/Network/Run/TCP.hs b/Network/Run/TCP.hs
--- a/Network/Run/TCP.hs
+++ b/Network/Run/TCP.hs
@@ -12,47 +12,28 @@
 import Control.Monad (forever, void)
 import Network.Socket
 
+import Network.Run.Core
+
 -- | Running a TCP client with a connected socket.
-runTCPClient :: HostName -> ServiceName -> (Socket -> IO a) -> IO a
-runTCPClient host port client = withSocketsDo $ do
-    addr <- resolve
-#if MIN_VERSION_network(3,1,1)
-    E.bracket (open addr) (\sock -> gracefulClose sock 5000) client
-#else
-    E.bracket (open addr) close client
-#endif
+runTCPClient :: String -> String -> (Socket -> IO a) -> IO a
+runTCPClient host port client = runClient Stream host port client'
   where
-    resolve = do
-        let hints = defaultHints { addrSocketType = Stream }
-        head <$> getAddrInfo (Just hints) (Just host) (Just port)
-    open addr = do
-        sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
-        connect sock $ addrAddress addr
-        return sock
+    client' sock _peer = client sock
 
 -- | Running a TCP server with an accepted socket and its peer name.
-runTCPServer :: Maybe HostName -> ServiceName -> (Socket -> SockAddr -> IO a) -> IO a
+runTCPServer :: Maybe HostName -> ServiceName -> (Socket -> IO a) -> IO a
 runTCPServer mhost port server = withSocketsDo $ do
-    addr <- resolve
+    addr <- resolve Stream mhost port True
     E.bracket (open addr) close loop
   where
-    resolve = do
-        let hints = defaultHints {
-                addrFlags = [AI_PASSIVE]
-              , addrSocketType = Stream
-              }
-        head <$> getAddrInfo (Just hints) mhost (Just port)
     open addr = do
-        sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
-        setSocketOption sock ReuseAddr 1
-        withFdSocket sock $ setCloseOnExecIfNeeded
-        bind sock $ addrAddress addr
+        sock <- openServerSocket addr
         listen sock 1024
         return sock
     loop sock = forever $ do
-        (conn, peer) <- accept sock
+        (conn, _peer) <- accept sock
 #if MIN_VERSION_network(3,1,1)
-        void $ forkFinally (server conn peer) (const $ gracefulClose conn 5000)
+        void $ forkFinally (server conn) (const $ gracefulClose conn 5000)
 #else
-        void $ forkFinally (server conn peer) (const $ close conn)
+        void $ forkFinally (server conn) (const $ close conn)
 #endif
diff --git a/Network/Run/UDP.hs b/Network/Run/UDP.hs
new file mode 100644
--- /dev/null
+++ b/Network/Run/UDP.hs
@@ -0,0 +1,23 @@
+-- | Simple functions to run UDP clients and servers.
+module Network.Run.UDP (
+    runUDPClient
+  , runUDPServer
+  ) where
+
+import qualified Control.Exception as E
+import Network.Socket
+
+import Network.Run.Core
+
+-- | Running a UDP client with a socket.
+--   The client action takes a socket and
+--   server's socket address.
+--   They should be used with 'sendTo'.
+runUDPClient :: String -> String -> (Socket -> SockAddr -> IO a) -> IO a
+runUDPClient = runClient Datagram
+
+-- | Running a UDP server with an open socket.
+runUDPServer :: Maybe HostName -> ServiceName -> (Socket -> IO a) -> IO a
+runUDPServer mhost port server = withSocketsDo $ do
+    addr <- resolve Datagram mhost port True
+    E.bracket (openServerSocket addr) close server
diff --git a/network-run.cabal b/network-run.cabal
--- a/network-run.cabal
+++ b/network-run.cabal
@@ -1,5 +1,5 @@
 name:                network-run
-version:             0.0.1
+version:             0.1.0
 synopsis:            Simple network runner library
 description:         Simple functions to run network clients and servers.
 -- bug-reports:
@@ -14,7 +14,8 @@
 
 library
   exposed-modules:     Network.Run.TCP
-  -- other-modules:
+                       Network.Run.UDP
+  other-modules:       Network.Run.Core
   -- other-extensions:
   build-depends:       base >= 4 && < 5
                      , network >= 3.1.0
