Erlang Udp服务器丢弃大量数据包

时间:2015-09-06 14:45:35

标签: sockets erlang

我一直在测试运行udp服务器的各种语言/方法,以确定哪种语言/性能最高。到目前为止,我已经测试过.NET,NodeJs和Erlang。我发现这个代码片段丢失了超过我发送的50%的数据包,而node和.net的数量约为4%。方案是我尽快发送1000 20 byte messages并将一个递增的数字打印到屏幕上。 Erlang只获得了约400个。你可以建议我做些什么来改善这个结果吗?

-module(udp).
-export([start/0]).

start() ->
    spawn(fun() -> server(41235) end).

server(Port) ->
    {ok, Socket} = gen_udp:open(Port, [binary, {active, false}]),
    io:format("server opened socket:~p~n",[Socket]),
    loop(Socket,0).

loop(Socket,N) ->
    inet:setopts(Socket, [{active, once}]),
    receive
        {udp, Socket, Host, Port, Bin} ->
            io:format("~p~n",[N]),
            loop(Socket,N+1)
    end.
如果我完全搞砸了这个erlang代码,我不会感到惊讶。我有一段非常困难的时间围绕着一些概念。

我的服务器感激地借鉴了:http://erlycoder.com/83/erlang-udp-socket-usage-example-with-gen

如果您有兴趣,请联系我的客户:

namespace LocalUdpClient
{
    class Program
    {
        private static long _sentCount = 1;
        private static CustomQueue _queue;
        private static bool _continue = true;
        static void Main(string[] args)
        {
            _queue = new CustomQueue();
            _queue.ItemRemovedEventHandler += QueueOnItemRemovedEventHandler;
            PopulateQueue();
            var con = new System.Net.Sockets.UdpClient();
            con.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 41235));

            while (_continue)
            {
                byte[] bits = null;
                if (_queue.TryDequeue(out bits))
                {
                    con.SendAsync(bits, bits.Length);
                    Interlocked.Increment(ref _sentCount);
                    Console.Clear();
                    Console.Write(Interlocked.Read(ref _sentCount));
                }

            }

        }

        private static void QueueOnItemRemovedEventHandler(object sender, EventArgs eventArgs)
        {
            var queue = sender as CustomQueue;
            if (queue.Count <= 0)
            {
                Task.Run(() => PopulateQueue()).Wait();
            }
        }

        public static void PopulateQueue()
        {
            Console.ReadLine();
            RandomNumberGenerator rand2 = new RNGCryptoServiceProvider();
            Parallel.For(0, 1000, p =>
            {
                if (_queue.Count >= 1000) return;
                byte[] bytes = new byte[20];
                rand2.GetBytes(bytes);
                _queue.Enqueue(bytes);
            });



        }

    public class CustomQueue : ConcurrentQueue<byte[]>
    {
        public event EventHandler ItemRemovedEventHandler;

        new public bool TryDequeue(out byte[] item)
        {
            var x = base.TryDequeue(out item);
            if (ItemRemovedEventHandler != null)
            {
                ItemRemovedEventHandler(this,new EventArgs());
            }
            return x;

        }


    }
}

2 个答案:

答案 0 :(得分:3)

与保证传送的TCP不同,UDP数据包可能只是被丢弃。通常这将是溢出的结果。在您拥有生产者/消费者关系的任何地方,您都需要关注当生产者消费者时会发生什么。使用TCP流量控制会对发送方施加压力,但是UDP不存在这样的背压。

当您在服务器端打开UDP套接字时,它将分配一定量的内存以从网络接收数据。如果您的客户端没有像从网络到达的数据那样快速地从套接字读取,您将遇到缓冲区溢出,新的UDP数据包将覆盖以前接收但尚未读取的UDP数据包。

您可以使用rcvbuf和sndbuf选项增加套接字的接收(和传输)缓冲区的大小。但是,您可能必须首先增加内核限制(例如sysctl -w net.core.rmem_max)。

要查看是否丢失UDP数据包到内核缓冲区溢出,请使用netstat -su检查UDP统计信息(查看“数据包接收错误”)。

答案 1 :(得分:0)

我认为有些数据包丢失了,因为在发送时没有人主动期待它们。 您可以通过以下方式修改Erlang代码来进一步减少收到的数据包数量:

        io:format("~p~n",[N]),
        receive after 10 -> ok end,
        loop(Socket,N+1)

其中一个解决方案可能是使用{active, true}选项,这将确保数据包将被定向到监听过程中。邮箱中。

作为旁注,在我的机器上,原始代码可以达到~99%的数据包接收速率,但在添加延迟后,Erlang部分只能接收几十个数据包。