开发者

How do I capture and print stderr and/or stdout correctly on Windows?

开发者 https://www.devze.com 2023-04-09 18:33 出处:网络
Thanks to hammar I have the beginnings of a job management server running on windows. The intent is that a unix-side daemon will be sending commands to and receiving stderr/stdout from windows-side. P

Thanks to hammar I have the beginnings of a job management server running on windows. The intent is that a unix-side daemon will be sending commands to and receiving stderr/stdout from windows-side. Problem is, I can't get the windows-side server to either print to stderr/stdout on the windows side, nor can I send the stream to the handle connected to the unix side (using telnet client for now).

Here is my attempt. I'm only using stdout in this example, but neither stdout nor stderr works. runJob is the IO action where I am making my attempt. I would appreciate guidance in fixing this problem.

Edit: I ran a haskell test script in place of the .bat file, and it captures stdout/stderr. Below I am including the batch file. What puzzles me is when I run the batch file manually it produces stdout and stderr to screen. Can't figure out what is happening. Perhaps I should replace the batch file with a haskell script.

> import Network.Socket
> import Control.Monad
> import Network
> import System.Environment (getArgs)
> import System.Process
> import System.IO
> import Control.Concurrent (forkIO)
> import Control.Exception (bracket)
> import Data.Maybe

> main :: IO ()
> main = withSocketsDo $ do
>    putStrLn ("up top\n")
>    [port] <- getArgs
>    bracket (prepareSocket (fromIntegral $ read port))
>            sClose
>            acceptConnections

> prepareSocket :: PortNumber -> IO Socket
> prepareSocket port = do
>    sock <- socket AF_INET Stream defaultProtocol 
>    let socketAddress = SockAddrInet port 0000 
>    bindSocket sock socketAddress
>    listen sock 1
>    putStrLn $ "Listening on " ++ (show port)
>    return sock

> acceptConnections :: Socket -> IO ()
> acceptConnections sock' = do
>    forever $ do
>        (sock, sockAddr) <- Network.Socket.accept sock'
>        handle <- socketToHandle sock ReadWriteMode
>        sockHandler sock handle

> sockHandler :: Socket -> Handle -> IO ()
> sockHandler sock' handle = do
>     hSetBuffering handle LineBuffering
>     -- Add the forkIO back if you want to allow concurrent connections.
>     {- forkIO  $ -}
>     commandProcessor handle
>     return ()

> commandProcessor :: Handle -> IO ()
> commandProcessor handle = untilM (hIsEOF handle) handleCommand >> hClose handle
>   where
>     handleCommand = do
>         line <- hGetLine handle
>         let (cmd:arg) = words line
>         case cmd of
>             "echo" -> echoCommand handle arg 
>             "runjob" -> runJob handle arg
>             _ -> do hPutStrLn handle "Unknown command"

> echoCommand :: Handle -> [String] -> IO ()
> echoCommand handle arg = do
>     hPutStrLn handle (unwords arg)

> runJob :: Handle -> [String] -> IO ()
> runJob handle jobNumber = do
>        
>   --  let batchDirectory = "fookit" 
>     (_, Just hout, Just herr, jHandle) <-  
>         createProcess (proc testJob [])  { cwd = Just batchDirectory, 
>                                                    std_out = CreatePipe, 
>                                                    std_err = CreatePipe }
>  开发者_运维百科   stdOUT <- hGetLine herr
>     hPutStrLn stdout stdOUT
>     hPutStrLn handle stdOUT 
>     exitCode <- waitForProcess jHandle 
>    -- stdErr <- hShow hout                                           
>     --hPutStrLn handle stdOUT 
>     return ()

> batchDirectory = "C:\\Users\\ixia\\Documents"
> testJob = "C:\\Users\\ixia\\Documents\\680batch.bat"
> untilM cond action = do
>    b <- cond
>    if b
>      then return ()
>      else action >> untilM cond action

Here's the batch file I mentioned. It does what's expected when run manually

"C:\Program Files (x86)\Ixia\Tcl\8.4.14.0\bin\tclsh.exe" 680template.tcl


Let's try to narrow this down and make it easier to test by eliminating all the network code, as it really has nothing to do with capturing the output of a process. Here is a small test program extracted from your code.

import System.IO
import System.Process

main = do
    (_, Just hout, Just herr, jHandle) <-
        -- Replace with some other command on Windows
        createProcess (proc "/bin/date" [])
           { cwd = Just "."
           , std_out = CreatePipe
           , std_err = CreatePipe 
           }

    putStrLn "First line of stdout:"
    hGetLine hout >>= putStrLn

    exitCode <- waitForProcess jHandle
    putStrLn $ "Exit code: " ++ show exitCode

This works as expected on Ubuntu, at least. (I don't have a Windows box nearby at the moment).

$ runghc RunJob.hs
First line of stdout:
Wed Sep 28 22:28:37 CEST 2011
Exit code: ExitSuccess

I would start by testing that this works with your job. That should hopefully give you some clues on how to proceed from there.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号