Eine TCP sockets library für (aktuell) Haskell und Python
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
3.1KB

  1. module Socket where
  2. import qualified Network.Socket as Net
  3. import qualified System.IO as Sys
  4. import Control.Concurrent
  5. import Control.Concurrent.Chan
  6. import Control.Monad (forever)
  7. import Control.Monad.Reader
  8. import Data.List.Split
  9. data Buffering = NoBuffering
  10. | LengthBuffering
  11. | DelimiterBuffering String
  12. deriving (Show)
  13. data ServerEnv = ServerEnv
  14. { buffering :: Buffering -- ^ Buffermode
  15. , socket :: Net.Socket -- ^ the socket used to communicate
  16. , global :: Chan String
  17. , onReceive :: OnReceive
  18. }
  19. type Server = ReaderT ServerEnv IO
  20. type OnReceive = Sys.Handle -> Net.SockAddr -> String -> Server ()
  21. broadcast :: String -> Server ()
  22. broadcast msg = do
  23. bufmode <- asks buffering
  24. chan <- asks global
  25. case bufmode of
  26. DelimiterBuffering delim -> liftIO $ writeChan chan $ msg ++ delim
  27. _ -> liftIO $ writeChan chan msg
  28. send :: Sys.Handle -> String -> Server ()
  29. send connhdl msg = do
  30. bufmode <- asks buffering
  31. case bufmode of
  32. DelimiterBuffering delim -> liftIO $ Sys.hPutStr connhdl $ msg ++ delim
  33. _ -> liftIO $ Sys.hPutStr connhdl msg
  34. -- | Initialize a new server with the given port number and buffering mode
  35. initServer :: Net.PortNumber -> Buffering -> OnReceive -> IO ServerEnv
  36. initServer port buffermode handler = do
  37. sock <- Net.socket Net.AF_INET Net.Stream 0
  38. Net.setSocketOption sock Net.ReuseAddr 1
  39. Net.bind sock (Net.SockAddrInet port Net.iNADDR_ANY)
  40. Net.listen sock 5
  41. chan <- newChan
  42. forkIO $ forever $ do
  43. msg <- readChan chan -- clearing the main channel
  44. return ()
  45. return (ServerEnv buffermode sock chan handler)
  46. -- | Looping over requests and establish connection
  47. procRequests :: Server ()
  48. procRequests = do
  49. sock <- asks socket
  50. (conn, clientaddr) <- liftIO $ Net.accept sock
  51. env <- ask
  52. liftIO $ forkIO $ runReaderT (procMessages conn clientaddr) env
  53. procRequests
  54. -- | Handle one client
  55. procMessages :: Net.Socket -> Net.SockAddr -> Server ()
  56. procMessages conn clientaddr = do
  57. connhdl <- liftIO $ Net.socketToHandle conn Sys.ReadWriteMode
  58. liftIO $ Sys.hSetBuffering connhdl Sys.NoBuffering
  59. globalChan <- asks global
  60. commChan <- liftIO $ dupChan globalChan
  61. reader <- liftIO $ forkIO $ forever $ do
  62. msg <- readChan commChan
  63. Sys.hPutStrLn connhdl msg
  64. handler <- asks onReceive
  65. messages <- liftIO $ Sys.hGetContents connhdl
  66. buffermode <- asks buffering
  67. case buffermode of
  68. DelimiterBuffering delimiter ->
  69. mapM_ (handler connhdl clientaddr) (splitOn delimiter messages)
  70. LengthBuffering -> liftIO $ putStrLn (take 4 messages)
  71. _ -> return ()
  72. -- clean up
  73. liftIO $ do killThread reader
  74. Sys.hClose connhdl
  75. sampleHandler :: OnReceive
  76. sampleHandler connhdl addr query = do
  77. liftIO $ putStrLn $ "new query " ++ query
  78. send connhdl $ "> " ++ query
  79. main :: IO ()
  80. main = do
  81. env <- initServer 4242 LengthBuffering sampleHandler
  82. runReaderT procRequests env