2016-09-07 4 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 с. При создании 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.NetworkToHostOrder()' при десериализации. –

Смежные вопросы