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
には、ソースを再開可能にすることについてのものがありますが、シンクはありません。
将来の質問については、コードが実際にコンパイルされるようにすべてのインポートも含めてください。ソリューションをより簡単にテストできます。 – shang
ここでの実装のコンジットの側面とは無関係な軽微なコメント:ここでの実装は、着信接続ごとに専用のワーカースレッドを持つ代わりに、接続を一度に1つずつ受け入れます。それは意図的なのでしょうか? –
@shang - fair point、私は輸入品で更新しました。要点を追加してそれにリンクすることを意味しますが、私はそれを忘れました! – Impredicative