Небезопасное автоматическое заполнение структур в .Net, для кода сети - PullRequest
1 голос
/ 18 сентября 2011

Идея: быть в состоянии взять байты любой структуры, отправить эти байты через TcpClient (или через мой клиентский упаковщик), затем заставить получающий клиент загрузить эти байты и использовать указатели, чтобы «закрасить» их в новую структуру.

Проблема: он отлично читает байты в буфер;он отлично читает массив байтов на другом конце.Операция «рисования», однако, терпит неудачу.Я пишу новый Vector3 (1F, 2F, 3F);Я читаю Vector3 (0F, 0F, 0F) ... Очевидно, не идеально.

К сожалению, я не вижу ошибку - если она работает в одну сторону, она должна работать наоборот - и значения

Функции записи / чтения:

    public static unsafe void Write<T>(Client client, T value) where T : struct
    {
        int n = System.Runtime.InteropServices.Marshal.SizeOf(value);
        byte[] buffer = new byte[n];
        {
            var handle = System.Runtime.InteropServices.GCHandle.Alloc(value, System.Runtime.InteropServices.GCHandleType.Pinned);
            void* ptr = handle.AddrOfPinnedObject().ToPointer();
            byte* bptr = (byte*)ptr;

            for (int t = 0; t < n; ++t)
            {
                buffer[t] = *(bptr + t);
            }
            handle.Free();
        }

        client.Writer.Write(buffer);
    }

Разрыв строки

    public static unsafe T Read<T>(Client client) where T : struct
    {
        T r = new T();
        int n = System.Runtime.InteropServices.Marshal.SizeOf(r);
        {
            byte[] buffer = client.Reader.ReadBytes(n);
            var handle = System.Runtime.InteropServices.GCHandle.Alloc(r, System.Runtime.InteropServices.GCHandleType.Pinned);
            void* ptr = handle.AddrOfPinnedObject().ToPointer();
            byte* bptr = (byte*)ptr;

            for (int t = 0; t < n; ++t)
            {
                *(bptr + t) = buffer[t];
            }
            handle.Free();
        }
        return r;
    }

Помогите, пожалуйста,спасибо.

Редактировать:

Ну, одна из основных проблем заключается в том, что я получаю дескриптор временной копии, созданной при передаче значения структуры.

Edit2:

Изменение "T r = new T ();"на "объект г = новый T ();"и «return r» для «return (T) r» блокирует и распаковывает структуру и тем временем делает ее ссылкой, поэтому указатель фактически указывает на нее.

Однако, это медленно.Я получаю 13 500 - 14 500 операций записи / чтения в секунду.

Edit3:

OTOH, сериализация / десериализация Vector3 через BinaryFormatter получает около 750 операций записи / чтения в секунду.Так что Lot быстрее, чем я использовал.:)

Edit4:

Индивидуальная отправка поплавков получила 8 400 RW / сек.Внезапно я чувствую себя намного лучше об этом.:)

Редактировать5:

Проверено закрепление и освобождение выделения GCHandle;28 000 000 операций в секунду (по сравнению с 1 000 000 000 Int32 / int add + assign / second. Таким образом, по сравнению с целыми числами, это в 35 раз медленнее. Однако это все еще достаточно быстро).Обратите внимание, что вы, кажется, не в состоянии закрепить классы, даже если GCHandle прекрасно работает с автоматически упакованными структурами (GCHandle принимает значения типа «объект»).

Теперь, если ребята из C # обновят ограничения наТочка, в которой выделение указателя распознает, что «T» является структурой, я мог бы просто назначить непосредственно указателю, что ... Да, невероятно быстро.

Следующее: возможно тестирование записи / чтенияиспользуя отдельные темы.:) Посмотрите, как GCHandle действительно влияет на задержку отправки / получения.

Как выясняется:

Edit6:

        double start = Timer.Elapsed.TotalSeconds;
        for (t = 0; t < count; ++t)
        {
            Vector3 from = new Vector3(1F, 2F, 3F);
            // Vector3* ptr = &test;
            // Vector3* ptr2 = &from;
            int n = sizeof(Vector3);
            if (n / 4 * 4 != n)
            {
                // This gets 9,000,000 ops/second;
                byte* bptr1 = (byte*)&test;
                byte* bptr2 = (byte*)&from;
                // int n = 12;
                for (int t2 = 0; t2 < n; ++t2)
                {
                    *(bptr1 + t2) = *(bptr2 + t2);
                }
            }
            else
            {
                // This speedup gets 24,000,000 ops/second.
                int n2 = n / 4;
                int* iptr1 = (int*)&test;
                int* iptr2 = (int*)&from;
                // int n = 12;
                for (int t2 = 0; t2 < n2; ++t2)
                {
                    *(iptr1 + t2) = *(iptr2 + t2);
                }
            }
        }

Итак, в целом,Я не думаю, что GCHandle действительно замедляет ход событий.(Те, кто думают, что это медленный способ назначения одного Vector3 другому, помнят, что цель состоит в том, чтобы сериализовать структуры в буфер byte [] для отправки по сети. И, хотя это не то, что мы здесь делаем,это было бы довольно легко сделать с помощью первого метода).

Edit7:

Следующие получили 6 900 000 операций в секунду:

        for (t = 0; t < count; ++t)
        {
            Vector3 from = new Vector3(1F, 2F, 3F);
            int n = sizeof(Vector3);
            byte* bptr2 = (byte*)&from;
            byte[] buffer = new byte[n];
            for (int t2 = 0; t2 < n; ++t2)
            {
                buffer[t2] = *(bptr2 + t2);
            }
        }

... Помогите!У меня есть IntruigingPuzzlitus!: D

...