Вот некоторый код, реализующий небольшой принимающий сервер с использованием conduit
, network-conduit
и stm-conduit
. Он получает данные в сокете, а затем передает их через STM-канал в основной поток.
import Control.Concurrent (forkIO)
import Control.Concurrent.STM (atomically)
import Control.Concurrent.STM.TBMChan (newTBMChan, TBMChan())
import Control.Monad (void)
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.Trans.Class
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Data.Conduit
import qualified Data.Conduit.Binary as DCB
import Data.Conduit.Extra.Resumable
import Data.Conduit.Network (sourceSocket)
import Data.Conduit.TMChan (sinkTBMChan, sourceTBMChan, mergeSources)
import System.Directory (removeFile)
import System.IO
type BSChan = TBMChan ByteString
listenSocket :: Socket -> Int -> IO BSChan
listenSocket soc bufSize = do
chan <- atomically $ newTBMChan bufSize
forkListener chan
return chan
where
forkListener chan = void . forkIO $ listen soc 2 >> loop where
loop = do
(conn, _) <- accept soc
sourceSocket conn $$ sinkTBMChan chan
close conn
loop
main :: IO ()
main = do
soc <- socket AF_UNIX Stream 0
bind soc (SockAddrUnix "mysock")
socChan <- listenSocket soc 8
sourceTBMChan socChan $$ DCB.sinkHandle stdout
removeFile "mysock"
(В реальном приложении поток данных из сокета объединяется с некоторыми другими, поэтому я не обрабатываю его напрямую в слушателе).
Проблема в том, что там, где я ожидал, что это останется открытым до тех пор, пока основной поток не будет убит, вместо этого он завершается после получения первого сообщения в сокете. Я не могу понять, почему он это делает, если только приемник (на 2-й и последней строке) не завершает работу, как только видит конец первого потока данных. Могу ли я убедить его не делать этого? В Conduit
есть кое-что о том, как сделать источник возобновляемым, но не приемник.