Komplikacja z przesyłaniem struktury przez TCP

0

Witam, mam taki problem. Chce przesyłać widoczną strukturę (paczkaTCP) po TCP. Niestety kompilator pokazuje mi błędy w metodzie getBytes:

  1. jeżeli int size nie jest na sztywno to:

Wystąpił nieobsługiwany wyjątek typu „System.ArgumentException” w mscorlib.dll

Dodatkowe informacje: Typ 'NLPBot.KontrolerTCP.TCPIP+paczkaTCP' nie może zostać zorganizowany jako struktura niezarządzana; nie można obliczyć akceptowalnego rozmiaru ani przesunięcia.

  1. jeżeli int size jest na sztywno to:

Wystąpił nieobsługiwany wyjątek typu „System.TypeLoadException” w mscorlib.dll

Dodatkowe informacje: Nie można zorganizować pola 'drzewoWyprowadzenia' typu 'paczkaTCP': Definicja typu tego pola zawiera informacje o układzie, ale ma nieprawidłową kombinację typów zarządzanych/niezarządzanych lub nie można jej zorganizować.

W czym może być problem?

 using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;


namespace NLPSerwer
{
    class Program
    {
        //zdanie z czesciami mowy
        public struct slowoOgolne
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10000)]
            public string slowo;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10000)]
            public string bezokolicznik;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10000)]
            public string czescMowy;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10000)]
            public List<string> dodatkoweElementy;
        }

        //analiza frazowa
        public struct analizaFrazowaStrukturaElement
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string wyraz;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string bezokolicznik;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string czescMowy;
        }

        public struct analizaFrazowaStruktura
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string wyrazenie;
            public List<analizaFrazowaStruktura> listaWyrazen;
            public analizaFrazowaStrukturaElement element;

            public analizaFrazowaStruktura(bool empty)
            {
                wyrazenie = null;
                listaWyrazen = new List<analizaFrazowaStruktura>();
                element = new analizaFrazowaStrukturaElement();
            }
        }

        //analiza zaleznosciowa
        public struct analizaZaleznosciowaStruktura
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string wyraz;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string bezokolicznik;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string czescMowy;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string rodzic;
            public int rodzicID;

            public analizaZaleznosciowaStruktura(bool empty)
            {
                wyraz = null;
                bezokolicznik = null;
                czescMowy = null;
                rodzic = null;
                rodzicID = -1;
            }
        }

        public struct paczkaTCP
        {
            //z syntaksy do semantyki
            List<slowoOgolne> slowaZeZdania;
            analizaFrazowaStruktura drzewoWyprowadzenia;
            List<analizaZaleznosciowaStruktura> drzewoZaleznosciowe;
            //z semantyki do syntaksy
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string nowePytanie;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
            public string ocena;
        }

        public static paczkaTCP fromBytes(byte[] arr)
        {
            paczkaTCP str = new paczkaTCP();

            //int size = Marshal.SizeOf(str);
            int size = 1000000;
            IntPtr ptr = Marshal.AllocHGlobal(size);

            Marshal.Copy(arr, 0, ptr, size);

            str = (paczkaTCP)Marshal.PtrToStructure(ptr, str.GetType());
            Marshal.FreeHGlobal(ptr);

            return str;
        }

        public static byte[] getBytes(paczkaTCP str)
        {
            //int size = Marshal.SizeOf(str);
            int size = 1000000;
            byte[] arr = new byte[size];

            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(str, ptr, false);
            Marshal.Copy(ptr, arr, 0, size);
            Marshal.FreeHGlobal(ptr);
            return arr;
        }

        public static void Connecting(string _ipAddresKlienta, int _portKlienta, string _ipAddresSerwera, int _portSerwera, ref BinaryWriter _writer, ref BinaryReader _reader)
        {
            bool polaczono = false;
            //paczkaTCP strukturaPaczki = new paczkaTCP();

            //int wielkoscStrukturyPaczki = Marshal.SizeOf(strukturaPaczki);
            //byte[] byteArray = new byte[wielkoscStrukturyPaczki];

            TcpListener listener = new TcpListener(IPAddress.Parse(_ipAddresKlienta), _portKlienta);
            TcpClient externalClient = new TcpClient();

            listener.Start();
            while (!polaczono)
            {
                try
                {
                    externalClient.Connect(_ipAddresSerwera, _portSerwera); // próba połączenia
                    Console.WriteLine("Połączono...");
                    System.Threading.Thread.Sleep(500);
                    polaczono = true;
                }
                catch
                {
                    Console.WriteLine("Oczekiwanie na serwer...");
                }
            }
            TcpClient newClient = listener.AcceptTcpClient(); // akceptacja

            _writer = new BinaryWriter(externalClient.GetStream());
            _reader = new BinaryReader(newClient.GetStream());
        }

        public static void Listening(BinaryReader _reader, ref paczkaTCP _paczkaOdebrana)
        {
            Console.WriteLine("Nastąpiło nasłuchiwanie...");
            bool nadeszlaPaczka = false;
            paczkaTCP tmpPaczka = new paczkaTCP();
            //int wielkoscPaczki = Marshal.SizeOf(tmpPaczka);
            int wielkoscPaczki = 1000000;

            while (!nadeszlaPaczka)
            {
                Console.WriteLine("Nasłuchuje...");
                tmpPaczka = fromBytes(_reader.ReadBytes(wielkoscPaczki));
                if (tmpPaczka.nowePytanie != null)
                {
                    nadeszlaPaczka = true;
                    _paczkaOdebrana = tmpPaczka;
                    Console.WriteLine("Odebrano paczkę!");
                }
            }
        }

        public static void Sender(BinaryWriter _writer, paczkaTCP _paczkaDoWyslania)
        {
            int wielkoscPaczki = Marshal.SizeOf(_paczkaDoWyslania);
            byte[] byteArray = new byte[wielkoscPaczki];

            byteArray = getBytes(_paczkaDoWyslania);

            _writer.Write(byteArray);
        }

        public static void Main()
        {
            BinaryReader bReader = null;
            BinaryWriter bWriter = null;
            paczkaTCP paczkaOdebrana = new paczkaTCP();
            Connecting("127.0.0.1", 6996, "127.0.0.1", 2112, ref bWriter, ref bReader);
            Listening(bReader, ref paczkaOdebrana);
            Console.ReadKey();
        }
    }
}
2

Niepotrzebnie tak sobie utrudniasz życie. Utwórz klasy, a nie struktury i zserializuj je np. do XML i taki obiekt puść w sieć. Przy deserializacji nie będziesz musiał martwić się upakowaniem danych, bo zostanie odtworzony po drugiej stronie taki sam obiekt jaki wysłałeś.

Warunek jest taki, że klasa musi posiadać bezparamatrowy konstruktor i pola podlegające serializacji muszą być publiczne albo możesz zrobić [XmlIgnore].

Wzięte ze stacka (StringWritter'a i StringReader 'a możesz opakować w using):
Tutaj przykład metod rozszerzających:

    public static T Deserialize<T>(this string toDeserialize)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        StringReader textReader = new StringReader(toDeserialize);
        return (T)xmlSerializer.Deserialize(textReader);
    }

    public static string Serialize<T>(this T toSerialize)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        StringWriter textWriter = new StringWriter();
        xmlSerializer.Serialize(textWriter, toSerialize);
        return textWriter.ToString();
    }

Wartości przed nazwami zmiennych możesz zamienić na var.

1 użytkowników online, w tym zalogowanych: 0, gości: 1