diff --git a/Network/Socket/Enumerator.hs b/Network/Socket/Enumerator.hs
--- a/Network/Socket/Enumerator.hs
+++ b/Network/Socket/Enumerator.hs
@@ -11,33 +11,35 @@
 module Network.Socket.Enumerator
 	( enumSocket
 	, enumSocketFrom
+	, enumSocketTimed
 	, iterSocket
 	, iterSocketTo
+	, iterSocketTimed
 	) where
 import qualified Control.Exception as Exc
-import Control.Monad.IO.Class (MonadIO, liftIO)
+import           Control.Monad.IO.Class (MonadIO, liftIO)
 import qualified Data.ByteString as B
-import Data.Enumerator ((>>==))
+import           Data.Enumerator ((>>==))
 import qualified Data.Enumerator as E
 import qualified Network.Socket as S
-import Network.Socket.ByteString (sendMany, sendManyTo, recv, recvFrom)
+import           Network.Socket.ByteString (sendMany, sendManyTo, recv, recvFrom)
+import           System.Timeout (timeout)
 
 -- | Enumerate binary data from a 'S.Socket', using 'recv'. The socket
 -- must be connected.
+--
+-- The buffer size should be a small power of 2, such as 4096.
 enumSocket :: MonadIO m
            => Integer -- ^ Buffer size
            -> S.Socket
            -> E.Enumerator B.ByteString m b
-enumSocket bufferSize sock = loop where
-	intSize = fromInteger bufferSize
-	
-	loop (E.Continue k) = do
-		bytes <- try (recv sock intSize)
-		if B.null bytes
-			then E.continue k
-			else k (E.Chunks [bytes]) >>== loop
+enumSocket bufferSize sock = enumLoop $ \loop k -> do
+	let intSize = fromInteger bufferSize
 	
-	loop step = E.returnI step
+	bytes <- try (recv sock intSize)
+	if B.null bytes
+		then E.continue k
+		else k (E.Chunks [bytes]) >>== loop
 
 -- | Enumerate binary data from a 'S.Socket', using 'recvFrom'. The socket
 -- does not have to be connected. Each chunk of data received will be paired
@@ -46,40 +48,93 @@
                => Integer -- ^ Buffer size
                -> S.Socket
                -> E.Enumerator (B.ByteString, S.SockAddr) m b
-enumSocketFrom bufferSize sock = loop where
-	intSize = fromInteger bufferSize
+enumSocketFrom bufferSize sock = enumLoop $ \loop k -> do
+	let intSize = fromInteger bufferSize
 	
-	loop (E.Continue k) = do
-		(bytes, addr) <- try (recvFrom sock intSize)
-		if B.null bytes
-			then E.continue k
-			else k (E.Chunks [(bytes, addr)]) >>== loop
+	(bytes, addr) <- try (recvFrom sock intSize)
+	if B.null bytes
+		then E.continue k
+		else k (E.Chunks [(bytes, addr)]) >>== loop
+
+-- | Enumerate binary data from a 'Socket', using 'recv'. The socket must
+-- be connected.
+--
+-- The buffer size should be a small power of 2, such as 4096.
+--
+-- If any call to 'recv' takes longer than the timeout, 'enumSocketTimed'
+-- will throw an error. To add a timeout for the entire session, wrap the
+-- call to 'E.run' in 'timeout'.
+--
+-- Since: 0.1.2
+enumSocketTimed :: MonadIO m
+                => Integer -- ^ Buffer size
+                -> Integer -- ^ Timeout, in microseconds
+                -> S.Socket
+                -> E.Enumerator B.ByteString m b
+enumSocketTimed bufferSize maxWait sock = enumLoop $ \loop k -> do
+	let intSize = fromInteger bufferSize
+	    intWait = fromInteger maxWait
+	    timedOut = Exc.ErrorCall "enumSocketTimed: timeout exceeded"
 	
-	loop step = E.returnI step
+	tried <- try (timeout intWait (recv sock intSize))
+	case tried of
+		Nothing -> E.throwError timedOut
+		Just bytes -> if B.null bytes
+			then E.continue k
+			else k (E.Chunks [bytes]) >>== loop
 
 -- | Write data to a 'S.Socket', using 'sendMany'. The socket must be connected.
 iterSocket :: MonadIO m
            => S.Socket
            -> E.Iteratee B.ByteString m ()
-iterSocket sock = E.continue step where
-	step E.EOF = E.yield () E.EOF
-	step (E.Chunks []) = E.continue step
-	step (E.Chunks xs) = try (sendMany sock xs) >> E.continue step
+iterSocket sock = foldMany (\xs -> try (sendMany sock xs))
 
 -- | Write data to a 'S.Socket', using 'sendManyTo'. The socket does not
 -- have to be connected.
 iterSocketTo :: MonadIO m
-           => S.Socket
-           -> S.SockAddr
-           -> E.Iteratee B.ByteString m ()
-iterSocketTo sock addr = E.continue step where
-	step E.EOF = E.yield () E.EOF
-	step (E.Chunks []) = E.continue step
-	step (E.Chunks xs) = try (sendManyTo sock xs addr) >> E.continue step
+             => S.Socket
+             -> S.SockAddr
+             -> E.Iteratee B.ByteString m ()
+iterSocketTo sock addr = foldMany (\xs -> try (sendManyTo sock xs addr))
 
+-- | Write data to a 'S.Socket', using 'sendMany'. The socket must be connected.
+--
+-- If any call to 'sendMany' takes longer than the timeout, 'iterSocketTimed'
+-- will throw an error. To add a timeout for the entire session, wrap the
+-- call to 'E.run' in 'timeout'.
+--
+-- Since: 0.1.2
+iterSocketTimed :: MonadIO m
+                => Integer -- ^ Timeout, in microseconds
+                -> S.Socket
+                -> E.Iteratee B.ByteString m ()
+iterSocketTimed maxWait sock = foldMany $ \xs -> do
+	let intWait = fromInteger maxWait
+	    timedOut = Exc.ErrorCall "iterSocketTimed: timeout exceeded"
+	
+	tried <- try (timeout intWait (sendMany sock xs))
+	case tried of
+		Nothing -> E.throwError timedOut
+		Just _ -> return ()
+
 try :: MonadIO m => IO b -> E.Iteratee a m b
 try io = do
 	tried <- liftIO (Exc.try io)
 	case tried of
 		Left err -> E.throwError (err :: Exc.SomeException)
 		Right b -> return b
+
+enumLoop :: Monad m
+         => ((E.Step a m b -> E.Iteratee a m b)
+          -> (E.Stream a -> E.Iteratee a m b)
+          -> E.Iteratee a m b)
+         -> E.Enumerator a m b
+enumLoop iter = loop where
+	loop (E.Continue k) = iter loop k
+	loop step = E.returnI step
+
+foldMany :: Monad m => ([a] -> E.Iteratee a m b) -> E.Iteratee a m ()
+foldMany f = E.continue step where
+	step E.EOF = E.yield () E.EOF
+	step (E.Chunks []) = E.continue step
+	step (E.Chunks xs) = f xs >> E.continue step
diff --git a/network-enumerator.cabal b/network-enumerator.cabal
--- a/network-enumerator.cabal
+++ b/network-enumerator.cabal
@@ -1,5 +1,5 @@
 name: network-enumerator
-version: 0.1.1
+version: 0.1.2
 synopsis: Enumerators for network sockets
 license: MIT
 license-file: license.txt
