Attempt to ReadAsync from SerialDevice silently crashes app - c#

I have a task that is running continuously reading from a serial port. I don't see any outward reason that this wouldn't work, but I don't discount that I could be missing something obvious.
if (serialPort != null)
{
while (true)
{
Windows.Storage.Streams.Buffer inputBuffer = new Windows.Storage.Streams.Buffer(1024);
Windows.Storage.Streams.Buffer resultBuffer = new Windows.Storage.Streams.Buffer(1024);
using (var childCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ReadCancellationTokenSource.Token))
{
var t = serialPort.InputStream.ReadAsync(inputBuffer, inputBuffer.Capacity, InputStreamOptions.Partial).AsTask(ReadCancellationTokenSource.Token);
resultBuffer = (Windows.Storage.Streams.Buffer)await t;
if (resultBuffer.Length > 0)
{
LogDebug(string.Format("Read {0} bytes", resultBuffer.Length));
DataReader dataReader = Windows.Storage.Streams.DataReader.FromBuffer(resultBuffer);
string resultString = dataReader.ReadString(resultBuffer.Length);
OnDataReceived(new DataReceiptEventArgs { Data = resultString });
}
}
await Task.Delay(10);
}
}
The result from this is that it reads correctly on the first iteration, but ReadAsync does not seem to handle no data on the stream gracefully when the next iteration happens and all the data has already been read. I would like the behavior to be that task did not return until data was available. At the very least, I would expect an exception, so I might be able to catch that the read failed.
Instead, the debugger logs a message that my app 'has exited with code -1073741811 (0xc000000d).' which is STATUS_INVALID_PARAMETER.
What am I doing wrong? Or will this really never work?
Edit:
This code produces the same error:
if (serialPort != null)
{
dataReaderObject = new DataReader(serialPort.InputStream);
LogDebug("Listening...");
while (true)
{
uint ReadBufferLength = 1024;
ReadCancellationTokenSource.Token.ThrowIfCancellationRequested();
dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;
using (var childCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ReadCancellationTokenSource.Token))
{
UInt32 bytesRead = 0;
bytesRead = await dataReaderObject.LoadAsync(ReadBufferLength).AsTask(childCancellationTokenSource.Token);
if (bytesRead > 0)
{
LogDebug(string.Format("Read {0} bytes", bytesRead));
string resultString = dataReaderObject.ReadString(bytesRead);
OnDataReceived(new DataReceiptEventArgs { Data = resultString });
}
}
await Task.Delay(10);
}
}

I think I figured it out.
As well as having a read thread going, I also was writing using a DataWriter. But my write method would dispose of the DataWriter on every write. Instead, I now have that declared as a private member of my serial class, and I instantiate the DataWriter upon connection and dispose of it in my close method.
This seems to keep communication going.
Not sure why this happens though, any explanations are welcome.

Related

Reading data from serial AT device

The only way I was able to read data from a serial AT device (that is a serial device that "speaks" only AT commands) was by reading one byte at a time.
The problem is that if I try to read more than I get from the device the code freezes, the LoadAsync method never returns. My solution was to read one byte at a time and use a cancellation token that would cancel the task if it did not return after some milliseconds.
public async Task<DeviceResponse> ReadStringInBatchAsync(int timeoutMilliseconds)
{
readCancellationTokenSource = new CancellationTokenSource();
readCancellationTokenSource.CancelAfter(timeoutMilliseconds);
Task<UInt32> loadAsyncTask;
DeviceDataReader.InputStreamOptions = InputStreamOptions.Partial;
UInt32 bytesRead = 0;
string response = string.Empty;
try
{
do
{
loadAsyncTask = DeviceDataReader.LoadAsync(1).AsTask(readCancellationTokenSource.Token);
bytesRead = await loadAsyncTask;
response += DeviceDataReader.ReadString(bytesRead);
} while (bytesRead > 0);
}
catch (Exception) { }
readCancellationTokenSource?.Dispose();
return new DeviceResponse() { FullResponse = response };
}
Any idea why this is happening? I tried with non-AT devices and there was no problem reading more than 1 byte. I have also tried with 2 different AT devices and both of them behaved the same way.

C# good practice waiting for TCP response

While making a c# application for remote controlling cisco routers using TCP, I got the problem of waiting for a response from the router.
For the application I have to connect to a Cisco router using a TCP connection. After the connection has been made a networkstream will push my command to the Cisco router. To let the router process the command, I am using Thread.Sleep. This is not the best solution.
Here is the complete code to get a idea what my program is doing.
string IPAddress = "192.168.1.1";
string message = "show running-config"; // command to run
int bytes;
string response = "";
byte[] responseInBytes = new byte[4096];
var client = new TcpClient();
client.ConnectAsync(IPAddress, 23).Wait(TimeSpan.FromSeconds(2));
if (client.Connected == true)
{
client.ReceiveTimeout = 3;
client.SendTimeout = 3;
byte[] messageInBytes = Encoding.ASCII.GetBytes(message);
NetworkStream stream = client.GetStream();
Console.WriteLine();
stream.Write(messageInBytes, 0, messageInBytes.Count()); //send data to router
Thread.Sleep(50); // temporary way to let the router fill his tcp response
bytes = stream.Read(responseInBytes, 0, responseInBytes.Length);
response = Encoding.ASCII.GetString(responseInBytes, 0, bytes);
return response; //whole command output
}
return null;
What is a good and reliable way to get the full response.
Thanks for any help or command.
More info:
The networksteam is always filled with something, most of the time it is filled with the cisco IOS login page. The biggest problem is to determine when the router is done filling up the response.
The response I most of the time get:
"??\u0001??\u0003??\u0018??\u001f\r\n\r\nUser Access Verification\r\n\r\nUsername: "
The return data will be diffent every time because it will be a result of a cisco command. This can vary from a short string to a very long string.
mrmathijs95 -
When reading from NetworkStream with Stream.Read it not 100% sure that you will read all expected data. Stream.Read can return when only few packet arrived and not waiting for others.
To be sure that you get all data use BinaryReader for reading.
BinaryReader.Read method will block current thread until all expected data arrived
private string GetResponse(string message)
{
const int RESPONSE_LENGTH = 4096;
byte[] messageInBytes = Encoding.ASCII.GetBytes(message);
bool leaveStreamOpen = true;
using(var writer = new BinaryWriter(client.GetStream()))
{
writer.Write(messageInBytes);
}
using(var reader = New BinaryReader(client.GetStream()))
{
byte[] bytes = reader.Read(RESPONSE_LENGTH );
return Encoding.ASCII.GetString(bytes);
}
}
Don't use Thread.Sleep. I would async/await the entire thing, given that you don't always know what the data is based on your recent edit. This is how I would do it (untested):
public class Program
{
// call Foo write with "show running-config"
}
public class Foo
{
private TcpClient _client;
private ConcurrentQueue<string> _responses;
private Task _continualRead;
private CancellationTokenSource _readCancellation;
public Foo()
{
this._responses = new ConcurrentQueue<string>();
this._readCancellation = new CancellationTokenSource();
this._continualRead = Task.Factory.StartNew(this.ContinualReadOperation, this._readCancellation.Token, this._readCancellation.Token);
}
public async Task<bool> Connect(string ip)
{
this._client = new TcpClient
{
ReceiveTimeout = 3, // probably shouldn't be 3ms.
SendTimeout = 3 // ^
};
int timeout = 1000;
return await this.AwaitTimeoutTask(this._client.ConnectAsync(ip, 23), timeout);
}
public async void StreamWrite(string message)
{
var messageBytes = Encoding.ASCII.GetBytes(message);
var stream = this._client.GetStream();
if (await this.AwaitTimeoutTask(stream.WriteAsync(messageBytes, 0, messageBytes.Length), 1000))
{
//write success
}
else
{
//write failure.
}
}
public async void ContinualReadOperation(object state)
{
var token = (CancellationToken)state;
var stream = this._client.GetStream();
var byteBuffer = new byte[4096];
while (!token.IsCancellationRequested)
{
int bytesLastRead = 0;
if (stream.DataAvailable)
{
bytesLastRead = await stream.ReadAsync(byteBuffer, 0, byteBuffer.Length, token);
}
if (bytesLastRead > 0)
{
var response = Encoding.ASCII.GetString(byteBuffer, 0, bytesLastRead);
this._responses.Enqueue(response);
}
}
}
private async Task<bool> AwaitTimeoutTask(Task task, int timeout)
{
return await Task.WhenAny(task, Task.Delay(timeout)) == task;
}
public void GetResponses()
{
//Do a TryDequeue etc... on this._responses.
}
}
I didn't expose the read cancellation publicly, but you could add this method to cancel the read operation:
public void Cancel()
{
this._readCancellation.Cancel();
}
And then dispose of your client and all that fun stuff.
Lastly, because you said there's always data available on the stream, where you're doing the read you may have to do some logic on the number of bytes last read to offset yourself within the stream if the data doesn't clear. You'll know if the responses you're getting is always the same.
This is the working code for me.
It uses the solution of Fabio,
combined with a while loop to check every X miliseconds if the response has changed.
client.ReceiveTimeout = 3;
client.SendTimeout = 3;
byte[] messageInBytes = Encoding.ASCII.GetBytes(message);
NetworkStream stream = client.GetStream();
Console.WriteLine();
using (var writer = new BinaryWriter(client.GetStream(),Encoding.ASCII,true))
{
writer.Write(messageInBytes);
}
using (var reader = new BinaryReader(client.GetStream(),Encoding.ASCII, true))
{
while (itIsTheEnd == false)
{
bytes = reader.Read(responseInBytes, 0, responseInBytes.Count());
if (lastBytesArray == responseInBytes)
{
itIsTheEnd = true;
}
lastBytesArray = responseInBytes;
Thread.Sleep(15);
}
}
response = Encoding.ASCII.GetString(responseInBytes);
Thanks for everyone who suggested a solution.
And thanks to Fabio for the given solution.

How can I constantly read the serial port in windows 10 universal (C#)

I want to read a serial port constantly and get the output in a textbox in my windows 10 universal app (C#). I found this code from the MS serial sample from https://github.com/ms-iot/samples/tree/develop/SerialSample/CS :
private async void Listen()
{
try
{
if (serialPort != null)
{
dataReaderObject = new DataReader(serialPort.InputStream);
while (true)
{
await ReadAsync(ReadCancellationTokenSource.Token);
}
}
}
catch (Exception ex)
{
if (ex.GetType().Name == "TaskCanceledException")
{
CloseDevice();
}
}
finally
{
if (dataReaderObject != null)
{
dataReaderObject.DetachStream();
dataReaderObject = null;
}
}
}
private async Task ReadAsync(CancellationToken cancellationToken)
{
Task<UInt32> loadAsyncTask;
uint ReadBufferLength = 1024;
cancellationToken.ThrowIfCancellationRequested();
dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;
loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(cancellationToken);
UInt32 bytesRead = await loadAsyncTask;
if (bytesRead > 0)
{
reciveTextBox.Text = dataReaderObject.ReadString(bytesRead);
}
}
but when I call the Listen() function with a button click, some times it reads the port sometimes it doesn't.
Please give a solution that will constantly read the serial port and give the output in the textbox.
The full code of MainPage.xaml.cs is here: http://pastebin.com/dmsTUBmT
I have an example on GitHub: Arduino_UWP_App
If to describe shortly.
Here are main variables:
private SerialDevice serialPort = null;
DataReader dataReaderObject = null;
Don't forget to reference:
using Windows.Devices.SerialCommunication;
using Windows.Devices.Enumeration;
using Windows.Storage.Streams;
First you should find device
string qFilter = SerialDevice.GetDeviceSelector("COM3");
DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(qFilter);
if (devices.Any())
{
string deviceId = devices.First().Id;
await OpenPort(deviceId);
}
In the way like this you could open port:
private async Task OpenPort(string deviceId)
{
serialPort = await SerialDevice.FromIdAsync(deviceId);
if (serialPort != null)
{
serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.BaudRate = 9600;
serialPort.Parity = SerialParity.None;
serialPort.StopBits = SerialStopBitCount.One;
serialPort.DataBits = 8;
serialPort.Handshake = SerialHandshake.None;
}
}
And now you can listen for messages:
while (true)
{
await Listen();
}
.......
private async Task Listen()
{
if (serialPort != null)
{
dataReaderObject = new DataReader(serialPort.InputStream);
await ReadAsync(ReadCancellationTokenSource.Token);
}
}
.......
private async Task ReadAsync(CancellationToken cancellationToken)
{
Task<UInt32> loadAsyncTask;
uint ReadBufferLength = 256; // only when this buffer would be full next code would be executed
dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;
loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(cancellationToken); // Create a task object
UInt32 bytesRead = await loadAsyncTask; // Launch the task and wait until buffer would be full
if (bytesRead > 0)
{
string strFromPort = dataReaderObject.ReadString(bytesRead);
}
}
It appears that by manipulating the read timeout one can receive different responses. The lower the number (milliseconds) the higher the speed of reading and the bytes read are closer or equal to what used to be BytesAvailable.
The higher the number the slower the response and with fuller read buffer (which might include more than one response from the source device).
The original SerialSample code would show this and if it is modified to perform predetermined timed writes in a loop then one could see the expected responses being read in a different way for each timeout value.
Those who experiment with PLC devices would probably be able to see this easily knowing what kind of response to expect from particular PLC.

A websocket's ReceiveAsync method does not await the entire message

I am receiving JSON through a websocket. At least: I am partially. Using an online websocket service I receive the full JSON response (all the HTML markup is ignored). When I look at the JSON that I receive in my console I can see the HTML markup (viewing it with the HTML viewer during debugging removes the HTML) but it ends abruptly (incomplete data).
My buffer has plenty of space and I am using async-await to (supposedly) wait for the entire response to come in before continuing.
private async Task Receive()
{
var buffer = new byte[4096 * 20];
while (_socket.State == WebSocketState.Open)
{
var response = await _socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (response.MessageType == WebSocketMessageType.Close)
{
await
_socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close response received",
CancellationToken.None);
}
else
{
var result = Encoding.UTF8.GetString(buffer);
var a = buffer[1000];
var b = buffer[10000];
var c = buffer[50000];
var d = buffer[81000];
Console.WriteLine(result);
var responseObject = JsonConvert.DeserializeObject<Response>(result, _requestParameters.ResponseDataType);
OnSocketReceive.Invoke(this, new SocketEventArgs {Response = responseObject });
buffer = new byte[4096 * 20];
}
}
}
Things to note: The buffer is perfectly big enough and b, c and d are never filled. I should also note that this only happens for the 1-questions-newest-tag-java request, 155-questions-active works perfectly fine.
After doing some digging I have found that response.CloseStatus and response.CloseStatusDescription are always null, response.Count is always 1396 (copy-pasting the result in Word does show that there are always 1396 characters) and response.EndOfMessage is false.
Digging through some source code I have found that the DefaultReceiveBufferSize is 16 * 1024 (big enough) and the WebSocketGetDefaultKeepAliveInterval() refers to an external implementation (but the debugger shows 00:00:30).
It is not a matter of timeout since the debugger halts at the same moment the online service receives its response.
Why is my method continuing to execute when the socket has not yet received all data?
Just to complete #Noseratio response, the code would be something like this:
ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[8192]);
WebSocketReceiveResult result= null;
using (var ms = new MemoryStream())
{
do
{
result = await socket.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
ms.Seek(0, SeekOrigin.Begin);
if (result.MessageType == WebSocketMessageType.Text)
{
using (var reader = new StreamReader(ms, Encoding.UTF8))
{
// do stuff
}
}
}
Cheers.
I might be wrong, but I don't think you're always supposed to receive a complete WebSocket message at once. The server may be sending the message in chunks (that'd correspond to calling SendAsync with endOfMessage: false).
So, do await _socket.ReceiveAsync() in a loop and accumulate the received chunks, until WebSocketReceiveResult.EndOfMessage is true or an error has occured.
On a side note, you probably should be using WebSocket.CreateClientBuffer instead of new ArraySegment<byte>(buffer).
// Read the bytes from the web socket and accumulate all into a list.
var buffer = new ArraySegment<byte>(new byte[1024]);
WebSocketReceiveResult result = null;
var allBytes = new List<byte>();
do
{
result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
for (int i = 0; i < result.Count; i++)
{
allBytes.Add(buffer.Array[i]);
}
}
while (!result.EndOfMessage);
// Optional step to convert to a string (UTF-8 encoding).
var text = Encoding.UTF8.GetString(allBytes.ToArray(), 0, allBytes.Count);
Following Noseratio's answer I have implemented a temporary buffer that will construct the data of the entire message.
var temporaryBuffer = new byte[BufferSize];
var buffer = new byte[BufferSize * 20];
int offset = 0;
WebSocketReceiveResult response;
while (true)
{
response = await _socket.ReceiveAsync(
new ArraySegment<byte>(temporaryBuffer),
CancellationToken.None);
temporaryBuffer.CopyTo(buffer, offset);
offset += response.Count;
temporaryBuffer = new byte[BufferSize];
if (response.EndOfMessage)
{
break;
}
}
Full implementation here
Try this:
try
{
WebSocketReceiveResult result;
string receivedMessage = "";
var message = new ArraySegment<byte>(new byte[4096]);
do
{
result = await WebSocket.ReceiveAsync(message, DisconectToken);
if (result.MessageType != WebSocketMessageType.Text)
break;
var messageBytes = message.Skip(message.Offset).Take(result.Count).ToArray();
receivedMessage += Encoding.UTF8.GetString(messageBytes);
}
while (!result.EndOfMessage);
if (receivedMessage != "{}" && !string.IsNullOrEmpty(receivedMessage))
{
ResolveWebSocketResponse.Invoke(receivedMessage, Connection);
Console.WriteLine("Received: {0}", receivedMessage);
}
}
catch (Exception ex)
{
var mes = ex.Message;
}

Read continous bytestream from Stream using TcpClient and Reactive Extensions

Consider the following code:
internal class Program
{
private static void Main(string[] args)
{
var client = new TcpClient();
client.ConnectAsync("localhost", 7105).Wait();
var stream = client.GetStream();
var observable = stream.ReadDataObservable().Repeat();
var s = from d in observable.Buffer(4)
let headerLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(d.ToArray(), 2))
let b = observable.Take(headerLength)
select b.ToEnumerable().ToArray();
s.Subscribe(a => Console.WriteLine("{0}", a));
Console.ReadLine();
}
}
public static class Extensions
{
public static IObservable<byte> ReadDataObservable(this Stream stream)
{
return Observable.Defer(async () =>
{
var buffer = new byte[1024];
var readBytes = await stream.ReadAsync(buffer, 0, buffer.Length);
return buffer.Take(readBytes).ToObservable();
});
}
}
Basically I want to parse the messages I receive with Reactive Extensions. The header of the message is parsed correctly using the Buffer(4) and I get the length of the remainder of the message. The problem that arises is that when I do stream.Take(headerLength), the code reevaluates the whole "chain" and tries to get a new message from the stream instead of returning the rest of the bytes which already has been read from the stream. To be more exact, the first ReadAsync(...) returns 38 bytes, the Buffer(4) returns the first 4 of those, the observable.Take(headerLength) does not return the remainding 34 bytes but instead tries to read a new message with ReadAsync.
The question is, how can I make sure the observable.Take(headerLength) receives the already read 34 bytes and not try to read a new message from the stream? I've searched around for a solution, but I can't really figure out how to achieve this.
Edit: This solution (Using Reactive Extensions (Rx) for socket programming practical?) is not what I'm looking for. This isn't reading everything available in the stream (up to buffersize) and makes a continous bytestream out of it. To me this solution doesn't seem like a very efficient way to read from a stream, hence my question.
This approach isn't going to work. The problem is the way you are using the observable. Buffer will not read 4 bytes and quit, it will continually read 4 byte chunks. The Take forms a second subscription that will read overlapping bytes. You'll find it much easier to parse the stream directly into messages.
The following code makes a good deal of effort to clean up properly as well.
Assuming your Message is just this, (ToString added for testing):
public class Message
{
public byte[] PayLoad;
public override string ToString()
{
return Encoding.UTF8.GetString(PayLoad);
}
}
And you have acquired a Stream then you can parse it as follows. First, a method to read an exact number of bytes from a stream:
public async static Task ReadExactBytesAsync(
Stream stream, byte[] buffer, CancellationToken ct)
{
var count = buffer.Length;
var totalBytesRemaining = count;
var totalBytesRead = 0;
while (totalBytesRemaining != 0)
{
var bytesRead = await stream.ReadAsync(
buffer, totalBytesRead, totalBytesRemaining, ct);
ct.ThrowIfCancellationRequested();
totalBytesRead += bytesRead;
totalBytesRemaining -= bytesRead;
}
}
Then the conversion of a stream to IObservable<Message>:
public static IObservable<Message> ReadMessages(
Stream sourceStream,
IScheduler scheduler = null)
{
int subscribed = 0;
scheduler = scheduler ?? Scheduler.Default;
return Observable.Create<Message>(o =>
{
// first check there is only one subscriber
// (multiple stream readers would cause havoc)
int previous = Interlocked.CompareExchange(ref subscribed, 1, 0);
if (previous != 0)
o.OnError(new Exception(
"Only one subscriber is allowed for each stream."));
// we will return a disposable that cleans
// up both the scheduled task below and
// the source stream
var dispose = new CompositeDisposable
{
Disposable.Create(sourceStream.Dispose)
};
// use async scheduling to get nice imperative code
var schedule = scheduler.ScheduleAsync(async (ctrl, ct) =>
{
// store the header here each time
var header = new byte[4];
// loop until cancellation requested
while (!ct.IsCancellationRequested)
{
try
{
// read the exact number of bytes for a header
await ReadExactBytesAsync(sourceStream, header, ct);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
// pass through any problem in the stream and quit
o.OnError(new InvalidDataException("Error in stream.", ex));
return;
}
ct.ThrowIfCancellationRequested();
var bodyLength = IPAddress.NetworkToHostOrder(
BitConverter.ToInt16(header, 2));
// create buffer to read the message
var payload = new byte[bodyLength];
// read exact bytes as before
try
{
await ReadExactBytesAsync(sourceStream, payload, ct);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
o.OnError(new InvalidDataException("Error in stream.", ex));
return;
}
// create a new message and send it to client
var message = new Message { PayLoad = payload };
o.OnNext(message);
}
// wrap things up
ct.ThrowIfCancellationRequested();
o.OnCompleted();
});
// return the suscription handle
dispose.Add(schedule);
return dispose;
});
}
EDIT - Very hacky test code I used:
private static void Main(string[] args)
{
var listener = new TcpListener(IPAddress.Any, 12873);
listener.Start();
var listenTask = listener.AcceptTcpClientAsync();
listenTask.ContinueWith((Task<TcpClient> t) =>
{
var client = t.Result;
var stream = client.GetStream();
const string messageText = "Hello World!";
var body = Encoding.UTF8.GetBytes(messageText);
var header = BitConverter.GetBytes(
IPAddress.HostToNetworkOrder(body.Length));
for (int i = 0; i < 5; i++)
{
stream.Write(header, 0, 4);
stream.Write(body, 0, 4);
stream.Flush();
// deliberate nasty delay
Thread.Sleep(2000);
stream.Write(body, 4, body.Length - 4);
stream.Flush();
}
stream.Close();
listener.Stop();
});
var tcpClient = new TcpClient();
tcpClient.Connect(new IPEndPoint(IPAddress.Loopback, 12873));
var clientStream = tcpClient.GetStream();
ReadMessages(clientStream).Subscribe(
Console.WriteLine,
ex => Console.WriteLine("Error: " + ex.Message),
() => Console.WriteLine("Done!"));
Console.ReadLine();
}
Wrapping up
You need to think about setting a timeout for reads, in case the server dies, and some kind of "end message" should be sent by the server. Currently this method will just continually tries to receive bytes. As you haven't specced it, I haven't included anything like this - but if you do, then as I've written it just breaking out of the while loop will cause OnCompleted to be sent.
I guess what is needed here is Qactive: A Rx.Net based queryable reactive tcp server provider
Server
Observable
.Interval(TimeSpan.FromSeconds(1))
.ServeQbservableTcp(new IPEndPoint(IPAddress.Loopback, 3205))
.Subscribe();
Client
var datasourceAddress = new IPEndPoint(IPAddress.Loopback, 3205);
var datasource = new TcpQbservableClient<long>(datasourceAddress);
(
from value in datasource.Query()
//The code below is actually executed on the server
where value <= 5 || value >= 8
select value
)
.Subscribe(Console.WriteLine);
What´s mind blowing about this is that clients can say what and how frequently they want the data they receive and the server can still limit and control when, how frequent and how much data it returns.
For more info on this https://github.com/RxDave/Qactive
Another blog.sample
https://sachabarbs.wordpress.com/2016/12/23/rx-over-the-wire/

Categories

Resources