Socket Behaviour

Steinitz, Dominic J Dominic.J.Steinitz@BritishAirways.com
01 Jun 2001 15:27:48 Z


Apologies if you have received this request for help already.

Can anyone tell me why the following code doesn't work as expected? Both the server and client hang.

[dom@lhrtba8fd85 simptest]$ server 20000 &
[1] 2694
[dom@lhrtba8fd85 simptest]$ client lhrtba8fd85 20000
client: interrupted
[1]+  Broken pipe             server 20000
[dom@lhrtba8fd85 simptest]$ more log.txt
Starting logging
Hello world
[dom@lhrtba8fd85 simptest]$                                                    

So it looks like the hPutStrLn to the server's socket never completes. What's stopping it? On the client side, "Hello world" gets sent but the hGetLine never completes. I guess because the server for some reason can't send.

Dominic.

module Main(main) where

import System
import IO
import Socket

main :: IO ()
main = do prog <- getProgName
          args <- getArgs
          if (length args /= 2)
              then do putStrLn ("Use: " ++ prog ++ " <host> <port>")
                      exitWith (ExitFailure (-1))
              else return ()
          let host = args !! 0
              port = read (args !! 1) :: Int in
              client host (PortNumber (mkPortNumber port))

client :: Hostname -> PortID -> IO ()
client host port = 
   do sh <- connectTo host port
      hPutStr sh "Hello world"
      hFlush sh
      x <- hGetLine sh
      putStrLn x


module Main (main) where

import System
import IO
import Socket

main :: IO ()
main = do prog <- getProgName
          args <- getArgs
          if (length args /= 1) 
             then do putStrLn ("Use: " ++ prog ++ " <port>")
                     exitWith (ExitFailure (-1))
             else return ()
          let port = read (args !! 0) :: Int in
             server (PortNumber (mkPortNumber port))

-- The server function creates a socket to listen on the port and
-- loops to log messages. 

server :: PortID -> IO ()
server port = 
   do ofh <- openFile "log.txt" WriteMode
      hPutStrLn ofh "Starting logging"
      hFlush ofh
      socket <- listenOn port 
      (sh,host,portid) <- accept socket
      let loop = do b <- getBuffer sh 16
                    case b of
                       Full msg ->
                          do hPutStrLn ofh msg
                             hFlush ofh
                             loop
                       Partial msg ->
                          do hPutStrLn ofh msg
                             hFlush ofh
                             hPutStrLn sh "Finishing Logging"
                             hFlush sh
                             hPutStrLn ofh "Finishing logging"
                             hClose ofh
         in loop         

data Buffer = Full String | Partial String

getBuffer :: Handle -> Int -> IO Buffer
getBuffer h n =
   if (n <= 0)
      then return (Full "")
      else do x <- try (hGetChar h)
              case x of
                 Right c -> 
                    do xs <- getBuffer h (n-1)
                       case xs of
                          Full cs -> return (Full (c:cs))
                          Partial cs -> return (Partial (c:cs))
                 Left e -> if isEOFError e 
                              then return (Partial "")
                              else ioError e

-------------------------------------------------------------------------------------------------
21st century air travel     http://www.britishairways.com