0

マルチキャストで受信した MPEG2-TS データを解析しようとしています。問題は、受信メソッドがパケットをスキップすることがあることです。これは、連続する Receive() メソッド間で行われる余分な処理に大きく依存していると思います [私が行った調査によると、CPU が Receive() メソッドにない場合、パケットは失われるため、バッファリングはすぐに処理しない最速のオプションであり、これを別のスレッドから実行するようにしておきます...私は正しいですか?].

現在、dequeue メソッドを使用して別のスレッドから後で処理するために、受信したデータグラムを保存するためにキューを使用しています。また、非同期レシーバーの代わりに、新しいスレッドで初期化されたブロッキング マルチキャスト レシーバーの使用に切り替えて、あるスレッドから別のスレッドへの委譲で遅延が発生しないようにしました (たとえば、OnReceiveFrom() メソッドを使用する場合)。

マルチキャスト レシーバーのコードは次のとおりです。

class Multicast
{
    /// <summary>
    /// The possible Operating Modes allowed for this Multicast Class File
    /// </summary>
    public enum OperationMode
    {
        Client,
        Server
    };

    private IPAddress ipAddress;
    private int portNumber;
    private int interfaceIndex;
    private Socket socket;
    private EndPoint sourceOrDestination;
    private byte[] Data;
    private OperationMode operationMode;

    public Queue<byte[]> q = new Queue<byte[]>();

    public Multicast(string ipAddress, int portNumber, int interfaceIndex, OperationMode operationMode)
    {
        if (!IPAddress.TryParse(ipAddress, out this.ipAddress))
        {
            throw new Exception("Incorrect Argument Data. Unable to parse IP Address!");
        }
        this.portNumber = portNumber;
        this.interfaceIndex = interfaceIndex;
        this.operationMode = operationMode;
    }

    public void Start()
    {
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, portNumber); // Local IP and Port (if more than one NIC interface is available, this command must be altered!

        //socket.SetSocketOption(SocketOptionLevel.Udp,SocketOptionName.Broadcast,true);
        socket.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.NoDelay, 1);
        socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1); // Allow for loopback testing 
        socket.Bind(localEndPoint); // Extremly important to bind the Socket before joining multicast groups 
        socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, Properties.Settings.Default.Network_MulticastTTL); // Set TTL (e.g.: 1 for one router hop)
        try
        {
            socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ipAddress, interfaceIndex)); // Join Multicast
        }
        catch (Exception) { }
        socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, Properties.Settings.Default.Network_FramePayloadSize);
        socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer, Properties.Settings.Default.Network_FramePayloadSize);
        //socket.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.DontFragment, 1);
        socket.DontFragment = true;



        while (true)
        {
            Data = new byte[socket.ReceiveBufferSize];
            socket.Receive(Data);

            q.Enqueue(Data);
        }
    }

    /// <summary>
    /// This function is used to stop the socket from sending/receiving further data. The socket is therefore closed.
    /// </summary>
    public void Stop()
    {
        socket.Close();
    }
}

受信したすべてのデータグラムを文字通り .ts ファイルにダンプしても、VLC で再生中にピクセル化や音声のスキップに気付くことがあります。実際には、wireshark がすべてのパケットを順番に表示するため、パケットは NIC カードによって正常に受信され、ストリームは VLC で問題なく再生できます (ストリームを直接開く場合)。

結果を改善するために何をお勧めしますか?

4

1 に答える 1

3

ソケットの受信バッファを約1つのデータグラムに制限していると思ったのと同じです。SetSocketOptionforに指定する値ReceiveBufferは大きくする必要があります。これにより、アプリがソケットからすぐに読み取っていない間(たとえば、現在の入力を処理している間)、カーネルにいくつかの入力データグラムをバッファリングするのに十分なスペースがあります。現在の受信バッファサイズの値に、たとえば100を掛けます。

次に、バイトがゼロであることについての返信コメントであなたが言っていることはあまり意味がありません。コードを見ると、の戻り値Receive()(つまり実際に受信したバイト数)は考慮されていません。代わりに、ReceiveBufferSize毎回バイトを取得すると想定しています。

于 2013-01-08T18:48:03.943 に答える