多线程服务器中的全局状态

时间:2014-07-19 19:09:42

标签: haskell state ttcpserver

我正在实施简单的http服务器 我希望我的回答取决于一些全球状态。例如,如果我收到请求' get_settings'我是第一次从同一个客户端发送大型设置json,第二次我将发送未经修改的' http响应。

像这样的东西

import Network.Simple.TCP

main = withSocketsDo $ do 
    let settings_state = 0 -- flag for settings response
    serve (Host "127.0.0.1") "23980" $ \(conn_sock, remote_addr) -> do
        putStrLn $ "TCP connection established from " ++ show remote_addr
        (Just inp) <- recv conn_sock 1024
        send conn_sock (process inp settings_state)

process :: B.ByteString -> Int -> B.ByteString
process inp flag
    | flag == 0 = ... -- return full response and change global flag
    | otherwise = ... -- return 'Not-modified'

问题是如何实现它?我想尽可能简单,手动,没有任何Monad变形金刚等等。让代码变得丑陋,但很简单。 感谢

1 个答案:

答案 0 :(得分:4)

由于更改旗帜明显有一些副作用,process的结果将在IO

process :: B.ByteString -> Int -> IO B.ByteString

由于您不想使用任何类型的monad转换器,因此需要将Int与一些可变引用进行交换。是的,您已正确阅读: 可变的几种类型,例如IORefMVarTVarMVector,{ {1}} ......为了保持简单,请坚持IORef

STRef

请注意,您没有为该标志提供任何逻辑,因此我只是增加了该值,但您可能想要执行其他操作(或将标志更改为process :: B.ByteString -> IORef Int -> IO B.ByteString process inp flag = do oldFlag <- readIORef flag if oldFlag == 0 then do modifyIORef' flag (+1) return bigJSONObject else return notModified )。请注意,如果要在多线程程序中安全地使用IORef Bool,还要使用atomicModifyIORef'

IORef

无论哪种方式,您都需要使用 oldFlag <- atomicModifyIORef' flag (\o -> (o+1,o)) 创建IORef,因此您的代码段会变成类似

的内容
newIORef value