non-blocking recv from UDP socket

Hi, Is is possible to get Network.Socket.ByteString.recv to be non-blocking (i.e. return directly even if no data is available) ? I have tried ti use setSocketOption sock NoDelay 1 but then I get the following error: setSocketOption: unsupported operation (Protocol not available) Here is the code if it may help (I'm on linux btw). sock <- socket AF_INET Datagram 17 -- 17 is IPPROTO_UDP addr <- inet_addr "127.0.0.1" bindSocket sock (SockAddrInet 44004 addr) setSocketOption sock NoDelay 1 -- <-- doesn't seem to work addr <- inet_addr "127.0.0.1" forever $ do sent <- sendTo sock "hello" (SockAddrInet 44005 addr) dat <- recv sock 5 -- <-- I'd like it to be non-blocking B.putStrLn dat threadDelay 1000000 -- 1 second Thanks, Thu

Hi Thu,
On Thu, Aug 26, 2010 at 11:13 AM, Vo Minh Thu
Is is possible to get Network.Socket.ByteString.recv to be non-blocking (i.e. return directly even if no data is available) ?
Unfortunately not.
I have tried ti use
setSocketOption sock NoDelay 1
but then I get the following error:
setSocketOption: unsupported operation (Protocol not available)
Sockets are already set to be non-blocking and the blocking semantics are implemented on top of non-blocking sockets using e.g. the select system call. It's not the recv syscall that blocks but the I/O manager who blocks you're thread because recv returned WOULD_BLOCK. The I/O manager calls threadWaitRead upon receiving this error. threadWaitRead puts the thread to sleep until the socket is readable (as indicated by select). We could perhaps implement a truly non-blocking API. Cheers, Johan

2010/8/26 Johan Tibell
Hi Thu,
On Thu, Aug 26, 2010 at 11:13 AM, Vo Minh Thu
wrote: Is is possible to get Network.Socket.ByteString.recv to be non-blocking (i.e. return directly even if no data is available) ?
Unfortunately not.
I have tried ti use
setSocketOption sock NoDelay 1
but then I get the following error:
setSocketOption: unsupported operation (Protocol not available)
Sockets are already set to be non-blocking and the blocking semantics are implemented on top of non-blocking sockets using e.g. the select system call. It's not the recv syscall that blocks but the I/O manager who blocks you're thread because recv returned WOULD_BLOCK. The I/O manager calls threadWaitRead upon receiving this error. threadWaitRead puts the thread to sleep until the socket is readable (as indicated by select).
Ok, that explains also why using fcntl directly on the fd didn't work either. So, I think I will go the FFI road and create my socket the way I want. Do you see another way?
We could perhaps implement a truly non-blocking API.
If it is widely useful, I guess it would be great. I don't mind writing some C and using the FFI though. Thanks for your answer, Thu

On Thu, Aug 26, 2010 at 1:08 PM, Vo Minh Thu
Ok, that explains also why using fcntl directly on the fd didn't work either. So, I think I will go the FFI road and create my socket the way I want. Do you see another way?
Not if you want a solution right now. You can still use Network.Socket.Internal to get hold of the file descriptor and that way your new function will work with the old Socket type.
If it is widely useful, I guess it would be great. I don't mind writing some C and using the FFI though.
OK. I don't quite have time to look into it right now. If someone could suggest an API (and then implement it) I would be happy to review the patches. -- Johan

Quoth Vo Minh Thu
Ok, that explains also why using fcntl directly on the fd didn't work either. So, I think I will go the FFI road and create my socket the way I want.
I have been doing this with TCP STREAM sockets for some time, for similar reasons and others, and as you surmised, it has worked fine. Donn Cave, donn@avvanta.com

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 8/26/10 05:13 , Vo Minh Thu wrote:
Is is possible to get Network.Socket.ByteString.recv to be non-blocking (i.e. return directly even if no data is available) ?
"What are you really trying to do?" The Haskelly solution to this is to use threads; let the thread reading the socket block and the main thread synchronize with it somehow. (Haskell threads are very inexpensive; don't be afraid of them.) - -- brandon s. allbery [linux,solaris,freebsd,perl] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.10 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkx2mn4ACgkQIn7hlCsL25U2fQCgjHzzO3f61z7GeyVZfJIaet7k vE4An1CaiqTke6BdpuvYsg5U0d+n3Ig7 =QcGa -----END PGP SIGNATURE-----

2010/8/26 Brandon S Allbery KF8NH
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 8/26/10 05:13 , Vo Minh Thu wrote:
Is is possible to get Network.Socket.ByteString.recv to be non-blocking (i.e. return directly even if no data is available) ?
"What are you really trying to do?"
The Haskelly solution to this is to use threads; let the thread reading the socket block and the main thread synchronize with it somehow. (Haskell threads are very inexpensive; don't be afraid of them.)
Well, I have written the FFI and it works fine. What I'm doing is the networking part of a game loop following some nice ressource[0]. I'll wait a bit to have more experience with the code before changing how it is designed (e.g. using light threads). Fast paced 3D action games (and physics) networking seems quite involved. At first sight for instance, it seems easier to have an 'update' function for the networking code to detect timeout than to have it implemented on top of a waiting thread. (Such an update function is quite pervasive in a (imperative) game loop). Also the same socket is used both to read and write, so this would need additional synchronization. But thanks for the suggestion, it might be a good one later on. Cheers, Thu [0] http://gafferongames.wordpress.com/networking-for-game-programmers/
participants (4)
-
Brandon S Allbery KF8NH
-
Donn Cave
-
Johan Tibell
-
Vo Minh Thu