Socket Behaviour
Steinitz, Dominic J
Dominic.J.Steinitz@BritishAirways.com
31 May 2001 14:18:09 Z
Can anyone tell me why the following code doesn't work as expected? Both the server and client hang. If I run
server 20000 &
and
client <hostname> 20000
the server logfile produces
[dom@lhrtba8fd85 twotest]$ more log.txt
Thu May 31 14:35:39 BST 2001
Starting logging
Thu May 31 14:36:08 BST 2001
Hello world 48 65 6c 6c 6f 20 77 6f 72 6c 64
so it looks like the hPutStrLn to the socket never completes. On the client side, "Hello world" gets sent but the hGetLine never completes.
Client
do sh <- connectTo host port
hPutStr sh "Hello world"
hFlush sh
x <- hGetLine sh
putStrLn x
Server
socket <- listenOn port
(sh,host,portid) <- accept socket
let loop = do b <- getBuffer sh 16
case b of
Full msg ->
do logMessage ofh (hexedMessage msg)
loop
Partial msg ->
do logMessage ofh (hexedMessage msg)
hPutStrLn sh "Finishing Logging"
hFlush sh
logMessage ofh "Finishing logging"
hClose ofh
in loop
Dominic.
Here's the full code:
module Main (main) where
import System
import IO
import Time
import Socket
import Char
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
logMessage ofh "Starting logging"
socket <- listenOn port
(sh,host,portid) <- accept socket
let loop = do b <- getBuffer sh 16
case b of
Full msg ->
do logMessage ofh (hexedMessage msg)
loop
Partial msg ->
do logMessage ofh (hexedMessage msg)
hPutStrLn sh "Finishing Logging"
hFlush sh
logMessage 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
logMessage :: Handle -> String -> IO ()
logMessage hd msg =
do clock <- getClockTime
calendar <- toCalendarTime clock
hPutStrLn hd ((calendarTimeToString calendar) ++ "\n" ++ msg)
hFlush hd
showHex :: Char -> String
showHex x =
let y = ord x in
hexDigit (y `div` 16):hexDigit (y `mod` 16):[]
hexDigit :: Int -> Char
hexDigit x
| (0 <= x) && (x <= 9) = chr(ord '0' + x)
| (10 <= x) && (x <=16) = chr(ord 'a' + (x-10))
| otherwise = error "Outside hexadecimal range"
hexedMessage :: String -> String
hexedMessage msg =
(map toPrint msg) ++ " " ++ unwords (map showHex msg)
toPrint :: Char -> Char
toPrint x =
if ((isAscii x) && (not (isControl x)))
then x
else '.'
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
-------------------------------------------------------------------------------------------------
21st century air travel http://www.britishairways.com