打包任意数量坐标的udp数据包

本文关键字:udp 数据包 坐标 包任意 | 更新日期: 2023-09-27 18:06:17

所以我得到了一个可变数量的坐标(纬度和经度)。我想打包这些坐标在一个直接的方式,可以很容易地通过UDP发送和解包。我该如何用c#实现这一点呢?

我假设我声明了一个struct,然后使用内置的编组来获取要发送的字节数组。当涉及到可变数量的点时,如何做到这一点?

我的大部分编程经验都是用Python编写的,但我需要用c#来完成,而我对c#的经验有限。

编辑:我将添加一些我正在测试的代码,因为我觉得没有人只回复文本。

namespace ConsoleApplication1
{
    class Testing
    {
        static void Main(string[] args)
        {
            // Console.WriteLine("Starting");
            // string text = "Hello";
            // byte[] data = Encoding.ASCII.GetBytes(text);
            StartPacket test = new StartPacket();
            test.len = 3;
            List<double> points = new List<double>();
            points.Add(3.14);
            points.Add(5);
            points.Add(-1023.1231311);
            test.points = points;
            byte[] data = StructureToByteArray(test);
            SendUdp(65456, "192.168.20.100", data);
       }
        static void SendUdp(int srcPort, string dstIp, byte[] data)
        {
            Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
                                     ProtocolType.Udp);
            IPAddress dst = IPAddress.Parse(dstIp);
            IPEndPoint endPoint = new IPEndPoint(dst, srcPort);
            sock.SendTo(data, endPoint);
        }
        public struct StartPacket
        {
            public uint len;
            public List<double> points;
        }
        public static byte[] StructureToByteArray(object obj)
        {
            int len = Marshal.SizeOf(obj);
            byte[] arr = new byte[len];
            IntPtr ptr = Marshal.AllocHGlobal(len);
            Marshal.StructureToPtr(obj, ptr, true);
            Marshal.Copy(ptr, arr, 0, len);
            Marshal.FreeHGlobal(ptr);
            return arr;
        }
    }
}

这段代码失败了:"ConsoleApplication1类型。testrongtartpacket '不能被封送为非托管结构;无法计算有意义的大小或偏移量

打包任意数量坐标的udp数据包

这看起来更像是一个序列化/反序列化任务。最简单的方法是用Serializable标记类,然后像这样使用BinaryFormatter:

public class Program
{
    public static void Main(string[] args)
    {
        var startPacket = new StartPacket();
        startPacket.len = 3;
        startPacket.points = new List<double>() { 3.14, 5, -1023.1231311 };
        // serialize into a byte array for Socket.SendTo()
        var formatter = new BinaryFormatter();
        var ms = new MemoryStream();
        formatter.Serialize(ms, startPacket);
        var bytes = ms.ToArray();
        // assuming we received bytes[] from a socket, deserialize into StartPacket object
        ms = new MemoryStream(bytes);
        formatter = new BinaryFormatter();
        startPacket = (StartPacket)formatter.Deserialize(ms);
    }
}
[Serializable()]
public struct StartPacket
{
    public uint len;
    public List<double> points;
}

然而,这在内存方面不是很有效——这个示例生成一个524字节的序列化StartPacket,这可能是因为List<>的容量将超过3个double。将points设置为具有特定大小的数组只会使我们减少到211字节。在不深入研究的情况下,我猜在结构体的序列化版本中有很多开销(比如变量的名称和类型等)。但是,如果您不太关心数据包的大小,那么这可能适合您。

如果你想要更有效的东西,那么你可以像这样添加StartPacket方法:

public class Program
{
    public static void Main(string[] args)
    {
        var startPacket = new StartPacket();
        startPacket.len = 3;
        startPacket.points = new List<double> { 3.14, 5, -1023.1231311 };
        // create an array to send through the socket
        var arr = startPacket.ToArray();
        // create a StartPacket from an array we received from a socket
        var newStartPacket = StartPacket.FromArray(arr);
    }
}
public struct StartPacket
{
    public uint len;
    public List<double> points;
    public byte[] ToArray()
    {
        var arr = BitConverter.GetBytes(len);
        foreach (var point in points)
        {
            arr = arr.Concat(BitConverter.GetBytes(point)).ToArray();
        }
        return arr;
    }
    public static StartPacket FromArray(byte[] array)
    {
        var sp = new StartPacket();
        sp.len = BitConverter.ToUInt32(array, 0);
        sp.points = new List<double>();
        for (int i = 0; i < sp.len; i++)
        {
            sp.points.Add(BitConverter.ToDouble(array, 4 + i * 8));
        }
        return sp;
    }
}

请注意,这两个都不能解释系统的端序。