我正在尝试解析通过多播接收的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全部显示数据包,并且按顺序显示数据包,因此可以在VLC中正常播放数据包(直接打开流时)。
您建议如何改善结果?
答案 0 :(得分:3)
正如我以为您将套接字接收缓冲区限制为大约一个数据报。 SetSocketOption
给ReceiveBuffer
的值应该更大,因此内核有足够的空间为您缓冲多个输入数据报,而您的应用程序不会立即从套接字读取(比如处理当前输入)。将当前的接收缓冲区大小值乘以一百。
那么你所说的回答关于字节为零的评论没有多大意义。查看代码 - 您没有考虑Receive()
的返回值(即实际接收的字节数),而是假设每次都获得ReceiveBufferSize
个字节。