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+缓冲池的情况下,数据接收能力更好,丢包率更低