C#使用Span和SocketAsyncEventArgs

11

我想使用新的 Span 将非托管数据直接发送到套接字,但似乎 SocketAsyncEventArgs 只能接受无法用 byte *IntPtr 初始化的 Memory<byte>

所以,请问有没有办法在 SocketAsyncEventArgs 中使用 Span

感谢您的帮助。


2
你不能在异步方法中使用Span,这就是为什么要使用memory<T>。你没有说你如何获取未解码的数据,所以很难帮助...有一些Marshal函数可以返回一个Memory<>,你可以使用它们。 - C. Gonzalez
我有一段C代码,它返回guint8 *data; gsize size; - Teamol
2
如果您想“直接”发送非托管数据,则不应使用 SocketAsyncEventArgs。该类的整个目的是作为托管对象池中的一个单元,以减少分配。它试图实现与 Span 相同的目标,但以不同的方式(在 Span 不存在时)。要将非托管数据直接发送到套接字,您需要使用常规方法的 Span 版本(这已经在 此处 上进行了处理),但这不是异步的 - 由于 Span 的基于堆栈的特性,它们不能是异步的。 - Jeroen Mostert
理论上来说,可以构建一种新型的SocketAsyncEventArgs基础设施,它可以与非托管内存一起使用——你知道的,仅仅是因为我们还没有足够多的与套接字交互的方式。 :-P 然而我不认为它能很好地与当前的SocketAsyncEventArgs进行互操作。 - Jeroen Mostert
3个回答

4

正如评论中已经提到的,Span 在这里是错误的工具 - 你是否考虑过使用 Memory?正如你所说,SetBuffer 方法 将其作为参数接受 - 你不能使用它的原因是什么?

另请参阅 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
        }
    }
}

0

在 MSDN 页面上有一个完整的示例(以及类的实现)SocketAsyncEventArgs(只需跟随链接)。它展示了该类的正确使用方式,可能会给您所寻找的指导。

此外,正如 Shingo 所说,它应该全部使用托管代码,而不是指针。


0

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

如果不这样做,当C代码删除返回的指针时,发送的数据会发生什么?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接