0.前言
一个项目,使用C#做UDP组播通信,发现这个过程中有丢包现象,做个测试看看哪种方式更好。
测试工具:visual studio 2022
语言:C#
框架:.netframework 4.5
网络通信库:udpClinet、socket
方式:本机收发
1.数据发送端
数据发送端用C#编写的winfrom程序,使用的是udpClient,参考代码如下:
string msg="101010EF62";//测试发送的数据 string[] str; try { string ip = "224.0.0.85"; //组播地址 int port = 28889; //组播端口 System.Net.Sockets.UdpClient udpClient = new System.Net.Sockets.UdpClient(); str = Enumerable.Range(0, msg.Length / 2).Select(i => msg.Substring(i * 2, 2)).ToArray(); //分割成两个一组 byte[] res = new byte[str.Length]; for (int i = 0; i < str.Length; i++) { res[i] = Convert.ToByte(str[i], 16); //信息序号 } udpClient.Send(res, res.Length, new IPEndPoint(IPAddress.Parse(ip), port)); } catch (Exception ex) { Console.WriteLine(ex); }
注意,发送方式为没有任何间隔(一般做网络通信时要求有一定的间隔,来减少丢包率,此处为了测试性能,发送过程中没有任何间隔)
2.接收端-UdpClient方式
接收端为C#控制台程序(.netframework4.5),使用UdpClient默认方式如下:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace UDP_test { internal class Program { private static UdpClient udpClient; //UDP客户端 static void Main(string[] args) { udpClient = new UdpClient(28889); udpClient.JoinMulticastGroup(IPAddress.Parse("224.0.0.85")); // 加入组播组 int sum = 0;//计数器 Console.WriteLine("开始接收数据"); while (true) { // 接收数据 IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 28889); byte[] receiveData = udpClient.Receive(ref remoteEndPoint); string data = BitConverter.ToString(receiveData); //Console.WriteLine(data); sum = sum + 1; Console.WriteLine(DateTime.Now.ToString("mm:ss fff") + " 第" + sum); } } } }
发送211940条(每条按照218B计算,大概是211940*218/1024/1024=44MB),测试5次
发送持续时间 | 发送最后时间 | 接收最后时间 | 接收条数 |
206s | 47:14 105 | 47:14 107 | 204123 |
176s | 57:18 762 | 57:18 762 | 204026 |
151s | 02:20 506 | 02:20 506 | 199627 |
162s | 07:23 605 | 07:23 606 | 203649 |
174s | 14:20 019 | 14:20 019 | 202774 |
我们把缓冲区加大,代码参考如下:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace UDP_test { internal class Program { private static UdpClient udpClient; //UDP客户端 static void Main(string[] args) { udpClient = new UdpClient(28889); udpClient.JoinMulticastGroup(IPAddress.Parse("224.0.0.85")); // 加入组播组 int sum = 0;//计数器 Console.WriteLine("开始接收数据"); udpClient.Client.ReceiveBufferSize = 8*1024*1024; //设置缓冲区 while (true) { // 接收数据 IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 28889); byte[] receiveData = udpClient.Receive(ref remoteEndPoint); string data = BitConverter.ToString(receiveData); //Console.WriteLine(data); sum = sum + 1; Console.WriteLine(DateTime.Now.ToString("mm:ss fff") + " 第" + sum); } } } }
结果如下:
发送持续时间 | 发送最后时间 | 接收最后时间 | 接收条数 |
158s | 44:05 531 | 44:05 531 | 211940 |
164s | 50:14 850 | 50:14 850 | 211940 |
154s | 54:18 726 | 54:18 728 | 211940 |
153s | 59:04 861 | 59:04 867 | 211940 |
160s | 04:58 543 | 04:58 543 | 211940 |
结果发现并不丢包。
3.接收端—socket方式
参考代码如下:
//接收数据缓冲池 private static readonly ArrayPool<byte> BufferPool = ArrayPool<byte>.Shared; private void ReceiveData() { // 组播地址和端口 IPAddress multicastAddress = IPAddress.Parse("224.0.0.85"); int port = 28889; // 创建 UDP Socket Socket receiverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // 绑定到本地端口 IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, port); receiverSocket.Bind(localEndPoint); // 加入组播组 receiverSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastAddress, IPAddress.Any)); // 接收数据 while (true) { byte[] buffer = BufferPool.Rent(1024); EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); int length = receiverSocket.ReceiveFrom(buffer, ref remoteEndPoint); string message = BitConverter.ToString(buffer, 0, length); Console.WriteLine(message ); } }
经过测试,发现使用socket+缓冲池的情况下,数据接收能力更好,丢包率更低