Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Does Asynchronous UDP Datagram Haskell Server Have Packet Loss?

Tags:

haskell

I am sending simple UDP packets to this Haskell server. For a source of packets I use a plain text file generated by "aspell -l en dump master". However, any list of over 120,000 messages should work. If I start the consumer and producer at the same time, I do not loose packets. However, I want to be able to simulate a very busy consumer. If I introduce a threadDelay for 20 seconds before starting the consumer, I get packet loss. This to me is counter intuitive because I am doing less with standard out and disk IO when I delay consuming. Can anyone explain why I am getting loss with the delayed version? How can I manage the socket and TChan work better to not get any loss (just higher memory usage) while my consumer is very busy?

import Control.Monad (forever)
import Control.Concurrent (forkIO, threadDelay)
import Control.Concurrent.STM (writeTChan, readTChan, atomically)
import Control.Concurrent.STM.TChan
import Network.Socket hiding (send, sendTo, recv, recvFrom)
import Network.Socket.ByteString
import Data.ByteString hiding(putStrLn, head)
import qualified Data.ByteString.Char8 as Char8 (putStrLn, putStr)
import System.IO

main :: IO ()
main = withSocketsDo $  do
    hSetBuffering stdout NoBuffering
    addrinfos <- getAddrInfo
                 (Just (defaultHints {addrFlags = [AI_PASSIVE]}))
                 Nothing (Just "2000")
    let serveraddr = head addrinfos
    sock <- socket (addrFamily serveraddr) Datagram defaultProtocol
    bindSocket sock (addrAddress serveraddr)
    chan <- newTChanIO
    forkIO(producer chan sock)
    -- Uncomment the threadDelay below to see lossy version
    -- threadDelay (1000000 * 20)
    forkIO(consumer chan)
    forever $ threadDelay (1000000 * 60)

producer :: TChan ByteString -> Socket -> IO ()
producer chan sock = forever $ do
    (msg) <- recv sock 256
    atomically $ writeTChan chan msg

consumer :: TChan ByteString -> IO ()
consumer chan = forever $ do
    msg <- atomically $ readTChan chan
    Char8.putStr msg
like image 210
rrmckinley Avatar asked May 30 '12 20:05

rrmckinley


People also ask

What causes UDP packet loss?

The UDP packet loss is especially affected by TCP traffic and its flow control mechanism. This is because TCP flow control continues to increase its window size until packet loss occurs if the advertised window size is large enough.

Is UDP synchronous or asynchronous?

The Asynchronous Serial Traffic over UDP feature provides the ability to encapsulate asynchronous data into User Datagram Protocol (UDP) packets and then unreliably send this data without needing to establish a connection with a receiving device.

What percentage of UDP packets are dropped?

Less than 0.01% is not unusual. Packet loss due to congestion obviously depends on how busy the link is. If there is spare capacity along the entire path, this number will be 0%. But as the network gets busy, this number will increase.


1 Answers

Why would you not expect data loss? This would happen in any language, not just Haskell, because the kernel has only a limited amount of buffer space for each socket. Since, unlike TCP, UDP is not flow controlled, the kernel will just drop packets. You can of course increase your buffer size with the SO_RCVBUF socket option. But fundamentally UDP is not reliable anyway, so any real application using it needs to handle packet loss.

like image 54
user3188445 Avatar answered Nov 15 '22 07:11

user3188445