2016-09-07 14 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

これは、シリアライズ/デシリアライゼーションタスクのような感じです。この例では、おそらくに、524バイトのシリアル化さ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 }; 

     // 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; 
} 

:最も簡単な方法は、このようBinaryFormatterを使用Serializableを持つクラスをマークすることです事実、List<>は3つ以上の容量を有することになる。doubles。 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

ありがとう、これは便利です。エンディアンを指定できますか? – Shatnerz

+0

これは、あなたが実行しているアーキテクチャの特徴です。いくつかのプロセッサはリトルエンディアンであり、一部はビッグエンディアンです。デシリアライズ時に 'IPAddress.HostToNetworkOrder()'を使用し、トランスレーション用にシリアル化する場合は 'IPAddress.HostToNetworkOrder()'を使用して安全に再生できます。 –

関連する問題