2012-09-25 13 views
9

Estoy tratando de establecer el tiempo de espera de recepción en un socket construido con el módulo Network.Socket. He aquí un fragmento de código:Configuración de opciones de socket en OSX

import Network.Socket 

host = "127.0.0.1" 
port = PortNumber 3000 

main = do 
    addrinfos <- getAddrInfo Nothing (Just host) (Just port) 
    let serveraddr = head addrinfos 
    sock <- socket (addrFamily serveraddr) Stream defaultProtocol 
    setSocketOption sock RecvTimeOut 120000000 
    connect sock (addrAddress serveraddr) 
    msg <- recv sock 1024 
    putStrLn msg 
    sClose sock 

La línea setSocketOption lanza una excepción:

*** Exception: setSocketOption: invalid argument (Invalid argument) 

setSocketOption sólo acepta Int argumentos a favor de la configuración, pero no todas las opciones de conector quieren un Int. Específicamente RecvTimeOut y SendTimeOut esperan un struct timeval. ¿Hay alguna otra forma de establecer estas opciones desde haskell?

estoy corriendo GHC 7.4.2 en OSX 10.8.1

EDIT:

Network.Socket.Options parece ser la mejor solución a este problema, y ​​conseguir que para compilar en OSX resultó requerir sólo una pequeña solicitud de extracción. A partir de la versión 0.2.0.1, network-socket-options ahora compila en OSX.

EDITAR 2: No hubo suerte con Network.Socket.Options. La función setRecvTimeout no parece tener ningún efecto en OSX. Terminé usando timeout del paquete System.Timeout como una solución.

msg <- timeout 120000000 $ recv sock 1024 
+0

ayuda esto a: http: // www. haskell.org/pipermail/haskell/2005-October/016586.html? O esto: http://hackage.haskell.org/packages/archive/network-socket-options/0.2/doc/html/Network-Socket-Options.html? – paulsm4

+0

En Mac OS X y Linux, GHC utiliza E/S de socket sin bloqueo, que no se ve afectado por los tiempos de espera del socket. El uso de 'System.Timeout' es la forma correcta de finalizar las operaciones de E/S. Lamentablemente, [la E/S de red no se puede interrumpir actualmente en Windows] (https://github.com/haskell/network/issues/75), por lo que tendrá que usar el tiempo de espera del socket como solución temporal. Para la portabilidad, use los tiempos de espera del socket * y * 'System.Timeout'. –

Respuesta

2

leí sobre Haskell y definiciones struct desde aquí: http://therning.org/magnus/archives/315 . La definición estructura timeval del MSDN aquí (Es la misma estructura en GNU y probablemente en OSX): http://msdn.microsoft.com/en-us/library/windows/desktop/ms740560(v=vs.85).aspx

veces C-encabezado:

... 
typedef struct timeval { 
    long tv_sec; 
    long tv_usec; 
} timeval; 
.... 

Parece que es necesario definir algún tipo de estructura constructor en Haskell. O una unión completa de las cabeceras de tiempo como que (tomado de http://hackage.haskell.org/packages/archive/bindings-common/0.1.4/doc/html/src/CTypes.html):

   module CTypes where 
import Foreign 
import Foreign.C 

-- time.h 

data Tm = Tm { 
    tm'sec, 
    tm'min, 
    tm'hour, 
    tm'mday, 
    tm'mon, 
    tm'year, 
    tm'wday, 
    tm'yday, 
    tm'isdst :: CInt 
    } 

instance Storable Tm where 
    sizeOf _ = fromIntegral size_of_tm 
    alignment = sizeOf 
    peek p = 
     with 0 $ \p1 -> with 0 $ \p2 -> with 0 $ \p3 -> 
     with 0 $ \p4 -> with 0 $ \p5 -> with 0 $ \p6 -> 
     with 0 $ \p7 -> with 0 $ \p8 -> with 0 $ \p9 -> 
     c2hs_tm p p1 p2 p3 p4 p5 p6 p7 p8 p9 >> 
     peek p1 >>= \v1 -> peek p2 >>= \v2 -> peek p3 >>= \v3 -> 
     peek p4 >>= \v4 -> peek p5 >>= \v5 -> peek p6 >>= \v6 -> 
     peek p7 >>= \v7 -> peek p8 >>= \v8 -> peek p9 >>= \v9 -> 
     return $ Tm v1 v2 v3 v4 v5 v6 v7 v8 v9 
    poke p (Tm v1 v2 v3 v4 v5 v6 v7 v8 v9) = 
     hs2c_tm p v1 v2 v3 v4 v5 v6 v7 v8 v9 

foreign import ccall size_of_tm :: CInt 

foreign import ccall hs2c_tm 
    :: Ptr Tm -> CInt -> CInt -> CInt -> CInt -> 
     CInt -> CInt -> CInt -> CInt -> CInt -> IO() 

foreign import ccall c2hs_tm 
    :: Ptr Tm -> Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> 
     Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> 
     Ptr CInt -> IO() 

-- sys/time.h 

data Timeval = Timeval {timeval'tv_sec, timeval'tv_usec :: CLong} 

instance Storable Timeval where 

    sizeOf _ = fromIntegral size_of_timeval 

    alignment = sizeOf 

    peek p = 
     with 0 $ \p1 -> 
     with 0 $ \p2 -> 

     c2hs_timeval p p1 p2 >> 

     peek p1 >>= \v1 -> 
     peek p2 >>= \v2 -> 

     return $ Timeval {timeval'tv_sec = v1, timeval'tv_usec = v2} 

    poke p v = hs2c_timeval p (timeval'tv_sec v) (timeval'tv_usec v) 

foreign import ccall "size_of_timeval" size_of_timeval 
    :: CInt 

foreign import ccall "hs2c_timeval" hs2c_timeval 
    :: Ptr Timeval -> CLong -> CLong -> IO() 

foreign import ccall "c2hs_timeval" c2hs_timeval 
    :: Ptr Timeval -> Ptr CLong -> Ptr CLong -> IO() 

Un despojado a la versión necesaria sería:

module CTypes where 
import Foreign 
import Foreign.C 

-- sys/time.h 

data Timeval = Timeval {timeval'tv_sec, timeval'tv_usec :: CLong} 

A continuación, debería ser capaz de inicializar una estructura timeval por:

timeval <- Timeval { tv_sec=120 , tv_usec=0 } 

Espero que ayude un poco ...

Cuestiones relacionadas