I am trying to use Rx to read from a TCPClient receive stream and parse the data into an IObservable of string, delimited by newline “\r\n” The following is how I’m receiving from the socket stream…
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)));
Here is what I came up with to parse the string. This currently does not work…
obsStrings = messages.Buffer<string,string>(() =>
messages.Scan((a, c) => a + c).SkipWhile(a => !a.Contains("\r\n"))
);
The message subject receives the message in chunks so I’m trying to concat them and test whether the concatenated string contains newline, thus signaling the buffer to close and output the buffered chunks. Not sure why it isn’t working. Seems that I only get the first chunk out of obsStrings.
So I am looking for two things. I’d like to simplify reading of the io stream and eliminate the use of the messages subject. Secondly, I’d like to get my string parsing working. I have been hacking on this for a bit and cannot come up with a working solution. I am a beginner with Rx.
EDIT: Here is the finished product after the problem was solved….
var receivedStrings = socket.ReceiveUntilCompleted(SocketFlags.None)
.SelectMany(x => System.Text.Encoding.UTF8.GetString(x).ToCharArray())
.Scan(String.Empty, (a, b) => (a.EndsWith("\r\n") ? "" : a) + b)
.Where(x => x.EndsWith("\r\n"))
.Select(buffered => String.Join("", buffered))
.Select(a => a.Replace("\n", ""));
“ReceiveUntilCompleted” is an extension from the RXX project.
1 Answer