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