我很难从标准输出获取每个换行符的数据。数据由C程序产生。这是C代码:
// gcc counter.c -o counter
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
unsigned int i = 0;
while(1) {
printf("%d\n", i);
sleep(1);
i++;
}
}
我的目标是获得与下面的haskell函数相同的行为:
timeSource :: MonadIO m => Source m TL.Text
timeSource = forever $ do
now <- liftIO getCurrentTime
yield $ TL.pack $ show now
liftIO $ threadDelay 1000000
我尝试使用readProcess
模块中的readCreateProcess
和System.Process
。这是我的尝试之一:
counter :: MonadIO m => Source m TL.Text
counter = do
r <- liftIO $ readCreateProcess (proc "./counter" []) ""
-- r <- liftIO $ readProcess "./counter" [] []
yield $ TL.pack $ show r
liftIO $ threadDelay 1000000
这就是我在counter
中使用webSockets
函数的方式:
webSockets $ race_
(sourceWS $$ Data.Conduit.List.map TL.toUpper =$ sinkWSText)
-- (timeSource $$ sinkWSText)
(counter $$ sinkWSText)
当我打开http://localhost:3000/时,它不起作用。这是完整的代码。
{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-}
module Main where
import Yesod.Core
import Yesod.WebSockets
import qualified Data.Text.Lazy as TL
import Control.Monad (forever)
import Control.Concurrent (threadDelay)
import Data.Time
import Data.Conduit
import System.Process
import qualified Data.Conduit.List
data App = App
instance Yesod App
mkYesod "App" [parseRoutes|
/ HomeR GET
|]
timeSource :: MonadIO m => Source m TL.Text
timeSource = forever $ do
now <- liftIO getCurrentTime
yield $ TL.pack $ show now
liftIO $ threadDelay 1000000
counter :: MonadIO m => Source m TL.Text
counter = do
r <- liftIO $ readCreateProcess (proc "./counter" []) ""
-- r <- liftIO $ readProcess "./counter" [] []
yield $ TL.pack $ show r
liftIO $ threadDelay 1000000
getHomeR :: Handler Html
getHomeR = do
webSockets $ race_
(sourceWS $$ Data.Conduit.List.map TL.toUpper =$ sinkWSText)
(timeSource $$ sinkWSText)
-- (counter $$ sinkWSText)
defaultLayout $
toWidget
[julius|
var conn = new WebSocket("ws://localhost:3000/");
conn.onopen = function() {
document.write("<p>open!</p>");
document.write("<button id=button>Send another message</button>")
document.getElementById("button").addEventListener("click", function(){
var msg = prompt("Enter a message for the server");
conn.send(msg);
});
conn.send("hello world");
};
conn.onmessage = function(e) {
document.write("<p>" + e.data + "</p>");
};
conn.onclose = function () {
document.write("<p>Connection Closed</p>");
};
|]
main :: IO ()
main = warp 3000 App
所以我的问题是如何无限循环地访问每个printf
数据并在Haskell中使用它?
编辑1:
根据MathematicalOrchid的建议,这是我到目前为止所做的。
counter :: MonadIO m => Source m TL.Text
counter = do
r <- liftIO $ createProcess (proc "./counter" []){ std_out = CreatePipe, std_in = CreatePipe}
let (Just inp, Just outp, _, phandle) = r
liftIO $ hSetBuffering outp LineBuffering
contents <- liftIO $ hGetLine outp
yield $ TL.pack $ show contents
liftIO $ threadDelay 1000000
我想在进程终止之前它仍然会阻塞。
编辑2:
为了测试createProcess
是否有效,我尝试了此操作。
counterTest :: IO ()
counterTest = do
r <- createProcess (proc "./counter" []){ std_out = CreatePipe, std_in = CreatePipe}
let (Just inp, Just outp, _, phandle) = r
hSetBuffering outp LineBuffering
contents <- hGetLine outp
print contents
显然它仍在阻止。
答案 0 :(得分:2)
引用readProcess
的文档:
readProcess
派生一个外部进程,严格读取其标准输出,阻塞直到该进程终止,然后返回输出字符串。外部过程会继承标准错误。
(请注意。)看来readCreateProcess
的工作方式与此类似。
因此,基本上,当您调用此函数时,它将永远坐在那里等待您的外部进程退出。
我建议您像以前一样使用proc
创建一个CreateProcess
结构,将std_in
更改为CreatePipe
,然后调用createProcess
,这应该返回您您可以根据需要hGetLine
进行处理的句柄。
答案 1 :(得分:1)