2012-09-25 8 views
9

Ich versuche, das Empfangs-Timeout auf einem Sockel mit dem Network.Socket Modul zu setzen. Hier ist ein Code-Schnipsel:Einstellen der Socket-Optionen auf 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 

Die setSocketOption Linie löst eine Ausnahme:

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

setSocketOption nur Int Argumente für Einstellungen akzeptiert, aber nicht alle der Socket-Optionen wollen ein Int. Speziell RecvTimeOut und SendTimeOut erwarten Sie eine struct timeval. Gibt es eine andere Möglichkeit, diese Optionen aus Haskell zu setzen?

Ich bin mit GHC 7.4.2 auf OSX 10.8.1

EDIT:

Network.Socket.Options scheint die beste Lösung hier, und es immer auf OSX zu kompilieren nur ein stellte sich heraus zu verlangen winzige Pull-Anfrage. Ab Version 0.2.0.1 kompiliert network-socket-options jetzt auf OSX.

EDIT 2: Kein Glück mit Network.Socket.Options. Die setRecvTimeout Funktion scheint keine Auswirkungen auf OSX zu haben. Ich habe am Ende timeout aus dem System.Timeout-Paket als Workaround verwendet.

msg <- timeout 120000000 $ recv sock 1024 
+0

funktioniert diese Hilfe: http: // www. haskell.org/pipermail/haskell/2005-Oktober/016586.html? Oder das: http://hackage.haskell.org/packages/archive/network-socket-options/0.2/doc/html/Network-Socket-Options.html? – paulsm4

+0

Unter Mac OS X und Linux verwendet GHC nicht blockierende Socket-E/A, die nicht von Socket-Timeouts betroffen sind. Die Verwendung von 'System.Timeout 'ist die richtige Methode zum Timeout von E/A-Vorgängen. Leider kann [Netzwerk-E/A derzeit unter Windows nicht unterbrochen werden] (https://github.com/haskell/network/issues/75). Daher müssen Sie Socket-Timeouts als Workaround verwenden. Für die Portabilität verwenden Sie sowohl Socket-Timeouts * als auch * System.Timeout. –

Antwort

2

Ich las über Haskell und struct Definitionen von hier: http://therning.org/magnus/archives/315 . Die Struktur timeval Definition aus der MSDN hier (Es ist die gleiche Struktur auf GNU und wahrscheinlich auf OSX): http://msdn.microsoft.com/en-us/library/windows/desktop/ms740560(v=vs.85).aspx

die Zeit C-Header:

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

Es scheint, wie Sie irgendeine Art von Struktur definieren müssen Konstrukteur in Haskell. Oder eine vollständige Bindung an die Zeitschriften wie die (aus 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() 

Eine abgespeckte auf die erforderliche Version wäre:

module CTypes where 
import Foreign 
import Foreign.C 

-- sys/time.h 

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

Sie sollten dann in der Lage sein, eine timeval Struktur zu initialisieren von:

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

hoffe ich, dass hilft ein wenig ...