Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Rx恢复异步读取?_C#_System.reactive - Fatal编程技术网

C# 使用Rx恢复异步读取?

C# 使用Rx恢复异步读取?,c#,system.reactive,C#,System.reactive,今天还有一个问题:) 简单地说,我正在使用异步IO对流进行操作。然而,正如我们所知,当使用异步读取时,我们不一定能得到我们想要的所有字节-因此在XAsync方法上返回int。我想知道如何让RxObservable重新尝试读取未从流中读取正确字节数且偏移量正确的数据 目前,我有这个,但不知道如何在ReadAsync中设置offset参数 private IDisposable _streamMessageContract; private readonly byte[] _read

今天还有一个问题:)

简单地说,我正在使用异步IO对流进行操作。然而,正如我们所知,当使用异步读取时,我们不一定能得到我们想要的所有字节-因此在
XAsync
方法上返回int。我想知道如何让Rx
Observable
重新尝试读取未从流中读取正确字节数且偏移量正确的数据

目前,我有这个,但不知道如何在ReadAsync中设置offset参数

    private IDisposable _streamMessageContract;
    private readonly byte[] _readBuffer = new byte[8024];

    public void Start()
    {
        // Subscribe to the stream for dataz
        _streamMessageContract = Observable.FromAsync<int>(() => _stream.ReadAsync(_readBuffer, 0, _readBuffer.Length))
            .Repeat()
            .Subscribe(
                y => _RawBytesReceived(_readBuffer, y),
               ex => _Exception(ex),
               () => _StreamClosed());
    }

    #region Helpers
    private void _RawBytesReceived(byte[] bytes, int actualBytesRead)
    {
    }
    private void _StreamClosed()
    {
    }
    private void _Exception(Exception e)
    {
    }
    #endregion
private IDisposable\u streamMessageContract;
专用只读字节[]_readBuffer=新字节[8024];
公开作废开始()
{
//订阅dataz的流
_streamMessageContract=Observable.FromAsync(()=>_stream.ReadAsync(_readBuffer,0,_readBuffer.Length))
.重复
.订阅(
y=>_RawBytesReceived(_readBuffer,y),
ex=>_异常(ex),
()=>_StreamClosed());
}
#地区助手
private void _RawBytesReceived(字节[]字节,整数实际字节数)
{
}
私有void_StreamClosed()
{
}
私有无效(例外e)
{
}
#端区

最简单的方法是在闭包中使用局部变量,再加上
延迟
,强制可观察对象在每次迭代中重新评估其函数

假设您想在当前块完成后继续读取下一个块,您将得到如下结果

// An observable that will yield the next block in the stream.
// If the resulting block length is less than blockSize, then the
// end of the stream was reached.
private IObservable<byte[]> ReadBlock(Stream stream, int blockSize)
{
    // Wrap the whole thing in Defer() so that we
    // get a new memory block each time this observable is subscribed.
    return Observable.Defer(() =>
    {
        var block = new byte[blockSize];
        int numRead = 0;
        return Observable
            .Defer(() => Observable.FromAsync<int>(() =>
                stream.ReadAsync(block, numRead, block.Length - numRead)))
            .Do(y -=> numRead += y)
            .Repeat()
            .TakeWhile(y => y > 0 && numRead != blockSize) // take until EOF or entire block is read
            .LastOrDefaultAsync()  // only emit the final result of this operation
            .Select(_ =>
            {
                // If we hit EOF, then resize our result array to
                // the number of bytes actually read
                if (numRead < blockSize)
                {
                    block = block.Take(numRead).ToArray();
                }

                return block;
            });
    });
}

public void Start()
{
    // Subscribe to the stream for dataz.
    // Just keep reading blocks until
    // we get the final (under-sized) block
    _streamMessageContract = ReadBlock(stream, 8024)
        .Repeat()
        .TakeWhile(block => block.Length == 8024) // if block is small then that means we hit the end of the stream
        .Subscribe(
           block => _RawBytesReceived(block),
           ex => _Exception(ex),
           () => _StreamClosed());
}
//将在流中生成下一个块的可观察对象。
//如果生成的块长度小于blockSize,则
//到了小溪的尽头。
私有IObservable读块(流,int blockSize)
{
//用Defer()将整个过程包装起来,以便
//每次订阅此可观察对象时,获取一个新内存块。
返回可观察的延迟(()=>
{
var block=新字节[blockSize];
int numRead=0;
可观测回波
.Defer(()=>Observable.fromsync(()=>
stream.ReadAsync(block、numRead、block.Length-numRead)))
.Do(y-=>numRead+=y)
.重复
.TakeWhile(y=>y>0&&numRead!=blockSize)//直到读取EOF或整个块为止
.LastOrDefaultAsync()//仅发出此操作的最终结果
.选择(\u0=>
{
//如果我们点击EOF,那么将结果数组的大小调整为
//实际读取的字节数
if(numReadblock.Length==8024)//如果block很小,则意味着我们到达了流的末尾
.订阅(
block=>\u接收到的原始字节数(block),
ex=>_异常(ex),
()=>_StreamClosed());
}

同步流做完全相同的事情,
读取(
还返回一个int,表示可能返回的字节数少于您请求的字节数。我建议您实际上只需从到达的偏移量继续流式传输。例如,如果您请求10个字节并返回4个字节,您只需从偏移量4中再请求6个。有很多Rx解决方案可用于从.NET流读取。有我确信Rxx项目也有一个。我一直在读那个介绍,但有很多词我不懂。从一开始就开始;-)说真的,如果有什么不清楚的话,那么holla。这对每个人来说都很容易(假设他们从头到尾都读)唯一的问题是8024是最大大小的块,我没有使用固定长度的数据包,我使用的是前缀长度的数据包,因此数据包的大小不同。然后使用blocksize为4或前缀长度大小的任何值调用
ReadBlock
。然后使用
SelectMany
再次调用前缀长度为的
ReadBlock
t read.类似于
ReadBlock(stream,4)。SelectMany(p=>p==null?可观察。Return(null):ReadBlock(stream,BitConverter.ToInt32(p,0)).Repeat().TakeWhile(message=>message!=null)
并将ReadBlock更改为在遇到EOF时发出
null
,而不是发出较小大小的数组。前缀大小未知,因为它编码为可变长度整数(varint).这就是为什么我目前提供8024字节的缓冲区,让应用程序决定是否已读取消息,如果已读取,则清除该字节范围。您描述的是本质上不同的问题。我发布的代码是如何执行您最初要求的操作的示例,即在没有得到你要求的所有字节。希望有足够的字节让你继续你真正的问题。我很感激,但我的印象是,你提供的答案只有在它能够阅读完整的块时才有效,这显然不是我要找的:P尽管它仍然是我需要的答案