haskell - 从 Haskell 中的无限循环(C 程序)中获取每个换行符的数据
问题描述
我无法从标准输出中获取每个换行符的数据。数据由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
and readCreateProcess
fromSystem.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
显然它仍然处于阻塞状态。
解决方案
引用文档readProcess
:
readProcess
fork 一个外部进程,严格读取其标准输出,阻塞直到进程终止,并返回输出字符串。外部进程继承标准误差。
(注意强调。)看起来readCreateProcess
类似。
所以基本上当你调用这个函数时,它会永远坐在那里等待你的外部进程退出。
我建议您像以前一样使用proc
创建CreateProcess
结构,更改std_in
为 be CreatePipe
,然后调用createProcess
它应该返回一个句柄,您可以hGetLine
根据需要从中获取。
推荐阅读
- nservicebus - 将 NServiceBus Saga 与 ConversationId 相关联
- ios - 如何修复 Mapbox iOS 中未更新的自定义路线步骤
- error-handling - 如何将错误消息从 os.system 重定向到某个文件?
- java - 为什么找不到班级?JUnit Runner 错误
- ios - UITextField leftView 和 rightView 重叠问题 - iOS13
- java - 如何在 Java 中获取 Youtube 视频结果?
- vb.net - 枚举属性中的变量:需要常量表达式
- python-3.x - 列表元素的总和等于所需的数量(总和)
- python - Python中的字段替换
- jquery - 将悬停功能更改为在移动设备上单击/触摸