C#在SocketAsyncEventArgs中使用span

时间:2018-09-06 18:53:44

标签: c# sockets .net-core unsafe

我想使用新的Span使用SocketAsyncEventArgs直接将非托管数据发送到套接字,但是似乎SocketAsyncEventArgs仅接受Memory<byte>,而不能用{{1}进行初始化}或byte * r。

那么请问有没有一种方法可以对IntPt使用span?

谢谢您的帮助。

3 个答案:

答案 0 :(得分:4)

正如评论中已经提到的,Span是错误的工具-您是否考虑过使用Memory?如您所说,SetBuffer method确实接受它作为参数-是否有您不能使用它的原因?

另请参阅this article,以获取有关堆栈与堆分配如何应用于Span和Memory的良好解释。它包括一个使用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
        }
    }
}

答案 1 :(得分:0)

您应该首先将数据复制到托管内存,使用Marshal或Buffer类。

如果不考虑C代码何时删除返回的指针,发送数据将如何处理?

答案 2 :(得分:0)

在MSDN页面上有SocketAsyncEventArgs (just follow the link)的完整示例(该类的实现)。它显示了该类的正确用法,并可能为您提供所需的指导。

而且,正如Shingo所说,所有内容都应该在托管代码中,而不是指针中。