在C#中均匀分发UDP数据包

时间:2016-04-23 14:06:01

标签: c# sockets udp multicast mpeg

我正在编写用于通过多播传输MPEG-TS文件的软件。 我有两个关于流的问题 - 比特率控制和每秒数据包的均匀分配。

MPEG-TS具有固定的数据包大小 - 188字节。多亏了我知道我每秒要发送多少个数据包来输入文件的比特率。

因此,对于第一个问题,我使用stopWatch找到了简单但不好的解决方案:

private readonly IPAddress ipAddress;
    private readonly int port;
    private readonly UdpClient udpClient;
    private IPEndPoint endPoint;
    private byte[] mpegTsChunk;
    private bool disposed = false;

    public Server(IPAddress ipAddress, int port, IPAddress localAddress)
    {
        this.ipAddress = ipAddress;
        this.port = port;
        udpClient = new UdpClient();
        udpClient.JoinMulticastGroup(ipAddress, localAddress);
        endPoint = new IPEndPoint(ipAddress, port);
        mpegTsChunk = new byte[188];
    }


        private void SendMpegTsStream(Stream fileStream, int bitRate)
    {
        int index = 0, packetCounter = 0;
        int maxPacketPerSecond = bitRate/(mpegTsChunk.Length*8);
        Stopwatch stopWatch = new Stopwatch();
        var spin = new SpinWait();

        stopWatch.Start();
        while (true)
        {

            while (index < mpegTsChunk.Length)
            { 
                int bytesRead = fileStream.Read(mpegTsChunk, index, mpegTsChunk.Length - index );
                if (bytesRead == 0) return; 
                index += bytesRead;
            }
            if (index != 0) udpClient.Send(mpegTsChunk, mpegTsChunk.Length, endPoint);
            if (index != mpegTsChunk.Length) return;
            ++packetCounter;
            if (packetCounter >= maxPacketPerSecond)
            {
                /////To fix
                while (stopWatch.ElapsedMilliseconds < 1000) { spin.SpinOnce(); }
                packetCounter = 0;
                stopWatch.Restart();
            }
            index = 0;
        }
    }

它有两个问题: - 而(x){}非常重CPU - 这会产生非常不均匀的数据包 即:我有40Mbps的MPEG-TS。我想发送它,使用这种方式,我的程序将尝试在开始时发送尽可能多的数据包,因为它可以创建峰值 - 在这种情况下,它可以很容易地超过100Mbps,如果我有100mbps端口将产生问题。 Wireshark屏幕显示我对第二个问题的意思:

Wireshark packets/s screen

如何在一秒钟内均匀分发数千个数据包?例如,对于10Mbps,每秒要发送6900个数据包 - 并在一秒钟内均匀分配它们。

编辑:

Aboud while(x){} - 我已经添加了SpinOnce()并且CPU下降了很多,但我仍然认为这不是一个好方法。 - 不旋转 - 35-50%的CPU - SpinOnce() - 10-12%(调试时)

EDIT2: 不,这与链接的问题不同。我现在不关心当数据包离开我的计算机时会发生什么 - 现在我希望所有数据包以均匀的方式离开并担心以后接收。关于我的问题的链接问题中的解决方案与我的解决方案类似 - 尽可能多地发送数据包然后在剩下的时间内休眠 - 仍然会导致数据包分布不均匀。

EDIT3 /不完美答案:

过了一段时间我做了这个有效:

private void SendMpegTsStream(Stream fileStream, int bitRate)
    {
        int index = 0, packetCounter = 0;
        var maxPacketPerSecond = (float) bitRate/(mpegTsChunk.Length*8) < 1
            ? (float) bitRate/(mpegTsChunk.Length*8)
            : bitRate/(mpegTsChunk.Length*8);

        //To do: adapt speed depending on pc
        int timeToSleep = (float) bitRate/(mpegTsChunk.Length*8) < 1 ? 100 : bitRate > 10000000 ? 1 : 10;

        var stopWatch = new Stopwatch();

        stopWatch.Start();
        while (streaming)
        {
            while (index < mpegTsChunk.Length)
            {
                int bytesRead = fileStream.Read(mpegTsChunk, index, mpegTsChunk.Length - index);
                if (bytesRead == 0) return;
                index += bytesRead;
            }
            if (index != 0) udpClient.Send(mpegTsChunk, mpegTsChunk.Length, endPoint);
            if (index != mpegTsChunk.Length) return;
            ++packetCounter;
            index = 0;

            while (streaming && packetCounter > stopWatch.ElapsedMilliseconds*maxPacketPerSecond/1000)
            {
                Thread.Sleep(timeToSleep);
                if (packetCounter > 2000000000)
                {
                    packetCounter = 0;
                    stopWatch.Restart();
                }
            }
        }
    }

0 个答案:

没有答案