2016-09-07 59 views
0

所以我得到了一個可變數量的座標(經度和緯度)。我想以簡單直接的方式打包這些座標,可以通過UDP輕鬆發送並解壓縮。我怎樣才能用C#解決這個問題?包裝任意數量座標的udp包

我假設我聲明瞭一個struct,然後使用內置編組來獲取要發送的字節數組。當涉及的點數可變時,如何做到這一點?

我的大部分編程經驗都在Python中,但是我需要在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.Testing +的StartPacket」不能被編組爲不接受管理結構;無法計算出有意義的大小或偏移量。

回答

2

這看起來更像是一個序列化/反序列化任務。最簡單的方法是,以紀念與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 s的容量。製作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; 
    } 
} 

注意,無論這些賬戶在系統的字節序的。希望這可以幫助。

+0

謝謝這很有用。可以指定endianness嗎? – Shatnerz

+0

這是你正在運行的架構的一個特點......一些處理器是小端的,有些是大端的。當序列化傳輸時使用'IPAddress.HostToNetworkOrder()',反序列化時'IPAddress.NetworkToHostOrder()'可以安全地播放它。 –