C# 可观测网络IO解析

C# 可观测网络IO解析,c#,system.reactive,C#,System.reactive,我正在尝试使用Rx从TCPClient接收流读取数据,并将数据解析为IObservable of string,由换行符“\r\n”分隔。以下是我从套接字流接收数据的方式 var messages = new Subject<string>(); var functionReceiveSocketData = Observable.FromAsyncPattern<byte[], int, int, SocketFlags, int>

我正在尝试使用Rx从TCPClient接收流读取数据,并将数据解析为IObservable of string,由换行符“\r\n”分隔。以下是我从套接字流接收数据的方式

var messages = new Subject<string>();

var functionReceiveSocketData =
            Observable.FromAsyncPattern<byte[], int, int, SocketFlags, int>
            (client.Client.BeginReceive, client.Client.EndReceive);

Func<byte[], int, byte[]> copy = (bs, n) =>
        {
            var rs = new byte[buffer.Length];
            bs.CopyTo(rs, 0);
            return rs;
        };

Observable
    .Defer(() =>
            {
                var buffer = new byte[50];
                return
                    from n in functionReceiveSocketData(buffer, 0, buffer.Length, SocketFlags.None)
                select copy(buffer, n);
            }).Repeat().Subscribe(x => messages.OnNext(System.Text.Encoding.UTF8.GetString(x)));

“ReceiveUntlCompleted”是RXX项目的一个扩展。

您可以使用
主题
选择
而不是
订阅

.Repeat().Select(x=>System.Text.Encoding.UTF8.GetString(x))

现在假设这一切都进入了一个名为
messages
的新的可观察对象,那么接下来的问题就是这一行

var obsStrings = messages.Buffer<string,string>(() =>  
                messages.Scan((a, c) => a + c).SkipWhile(a => !a.Contains("\r\n"))
            );
它为Buffered提供了一个关于何时关闭窗口(当窗口包含时)的可观察值,并为Select提供了要连接的缓冲量。这将导致拆分字符串的新可观察性

一个问题是,你仍然可以在块的中间有一条新的线,这会导致问题。一个简单的想法是观察字符,而不是完整的字符串块,例如:

obstrings.Repeat().SelectMany(x=>System.Text.Encoding.UTF8.GetString(x.tocharray().ToObservable())

然后可以执行
消息。其中(c=>c!='\r')
跳过
\r
并将缓冲区更改为:

var obsStrings = messages.Buffer(() => messages.Where(x => x == '\n')))
                         .Select(buffered => String.Join("", buffered));

认为您需要
消息。其中(x=>x='\n')
不是
消息。其中(x=>x!='\n')
缓冲区中调用。也就是说,它会在每一行上中断缓冲区。仍然会从这个oberservable中获得不连贯的块。我想知道这是否是一个线程问题,测试是在另一个线程上进行的,缓冲会继续或提前中断,因此缓冲会变得不确定。
Buffer
命令不会提前中断,它不是基于时间的或类似的。如果没有更多的信息,或者没有一个“破坏”的例子,我很难知道如何提供帮助。我发现我不需要.Buffer(1);最后。
var obsStrings = messages.Buffer<string,string>(() =>  
                messages.Scan((a, c) => a + c).SkipWhile(a => !a.Contains("\r\n"))
            );
var obsStrings = messages.Buffer(() => messages.Where(x => x.Contains("\r\n")))
                         .Select(buffered => String.Join(buffered));
var obsStrings = messages.Buffer(() => messages.Where(x => x == '\n')))
                         .Select(buffered => String.Join("", buffered));
messages
    .Scan(String.Empty, (a, b) => (a.EndsWith("\r\n") ? "" : a) + b)
    .Where(x => x.EndsWith("\r\n"))