C # Использование span с SocketAsyncEventArgs - PullRequest
0 голосов
/ 06 сентября 2018

Я хотел бы использовать новый Span для отправки неуправляемых данных прямо в сокет, используя SocketAsyncEventArgs, но, похоже, SocketAsyncEventArgs может принимать только Memory<byte>, который нельзя инициализировать с помощью byte * или IntPt r.

Так, пожалуйста, есть ли способ использовать span с SocketAsyncEventArgs?

Спасибо за вашу помощь.

Ответы [ 3 ]

0 голосов
/ 18 сентября 2018

Как уже упоминалось в комментариях, Span - это не тот инструмент, который вы использовали - вы вместо этого взяли Memory ? Как вы сказали, метод SetBuffer принимает это как параметр - есть ли причина, по которой вы не можете его использовать?

См. Также эту статью для хорошего объяснения того, как распределение стека и кучи применяется к диапазону и памяти. Он включает в себя этот пример, используя readonly Memory<Foo> buffer:

public struct Enumerable : IEnumerable<Foo>
{
    readonly Stream stream;

    public Enumerable(Stream stream)
    {
        this.stream = stream;
    }

    public IEnumerator<Foo> GetEnumerator() => new Enumerator(this);

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

    public struct Enumerator : IEnumerator<Foo>
    {
        static readonly int ItemSize = Unsafe.SizeOf<Foo>();

        readonly Stream stream;
        readonly Memory<Foo> buffer;
        bool lastBuffer;
        long loadedItems;
        int currentItem;

        public Enumerator(Enumerable enumerable)
        {
            stream = enumerable.stream;
            buffer = new Foo[100]; // alloc items buffer
            lastBuffer = false;
            loadedItems = 0;
            currentItem = -1;
        }

        public Foo Current => buffer.Span[currentItem];

        object IEnumerator.Current => Current;

        public bool MoveNext()
        {
            if (++currentItem != loadedItems) // increment current position and check if reached end of buffer
                return true;
            if (lastBuffer) // check if it was the last buffer
                return false;

            // get next buffer
            var rawBuffer = MemoryMarshal.Cast<Foo, byte>(buffer);
            var bytesRead = stream.Read(rawBuffer);
            lastBuffer = bytesRead < rawBuffer.Length;
            currentItem = 0;
            loadedItems = bytesRead / ItemSize;
            return loadedItems != 0;
        }

        public void Reset() => throw new NotImplementedException();

        public void Dispose()
        {
            // nothing to do
        }
    }
}
0 голосов
/ 21 сентября 2018

На странице MSDN есть полный пример (и реализация класса) для SocketAsyncEventArgs (просто перейдите по ссылке) . Он показывает правильное использование класса и может дать вам руководство, которое вы ищете.

Кроме того, как сказал Шинго, все должно быть в управляемом коде, а не в указателях.

0 голосов
/ 17 сентября 2018

Сначала вы должны скопировать данные в управляемую память, использовать класс Marshal или Buffer.

Если не подумать, когда код C удалит возвращенный указатель, что будет с отправленными данными?

...