Example implementation of IDuplexPipe for a TCP server - c#

I've recently discovered the System.IO.Pipelines namespace and it looks interesting. I've been trying to implement the IDuplexPipe interface in the context of a simple TCP server which accepts connections and then communicates back and forth with the connected client.
However, I'm struggling to make it stable. It feels like I've misunderstood something fundamental. I've also been googling for reference implementations of the interface to guide me in the right direction.
This is to my knowledge the most complete document on System.IO.Pipelines out there. The exmple I've provided below is heavily borrowing from it.
https://github.com/davidfowl/DocsStaging/blob/master/Pipelines.md
https://devblogs.microsoft.com/dotnet/system-io-pipelines-high-performance-io-in-net/
My question: what would a typical implementation of the IDuplexPipe interface look like in the context of a TCP server?
Btw, this is what I have currently. The idea is to setup a new "duplex communication" by providing an established SslStream:
public class DuplexCommunication : IDuplexPipe
{
public PipeReader Input => _receivePipe.Reader;
public PipeWriter Output => _transmitPipe.Writer;
private readonly SslStream _stream;
// Data received from the SslStream will end up on this pipe
private readonly Pipe _receivePipe = new Pipe();
// Data that is to be transmitted over the SslStream ends up on this pipe
private readonly Pipe _transmitPipe = new Pipe();
private readonly CancellationToken _cts;
private Task _receive;
private Task _transmit;
public DuplexCommunication(SslStream stream, CancellationToken cts)
{
_stream = stream;
_cts = cts;
_receive = Receive();
_transmit = Transmit();
}
private async Task Receive()
{
Exception error = null;
try
{
while (!_cts.IsCancellationRequested)
{
var buffer = _receivePipe.Writer.GetMemory(1);
var bytes = await _stream.ReadAsync(buffer, _cts);
_receivePipe.Writer.Advance(bytes);
if (bytes == 0) {
break;
}
var flush = await _receivePipe.Writer.FlushAsync(_cts);
if (flush.IsCompleted || flush.IsCanceled)
{
break;
}
}
}
catch (Exception ex)
{
// This might be "stream is closed" or similar, from when trying to read from the stream
Console.WriteLine($"DuplexPipe ReceiveTask caugth an exception: {ex.Message}");
error = ex;
}
finally
{
await _receivePipe.Writer.CompleteAsync(error);
}
}
private async Task Transmit()
{
Exception error = null;
try
{
while (!_cts.IsCancellationRequested)
{
var read = await _transmitPipe.Reader.ReadAsync(_cts);
var buffer = read.Buffer;
if (buffer.IsEmpty && read.IsCompleted)
{
break;
}
foreach (var segment in buffer)
{
await _stream.WriteAsync(segment, _cts);
}
_transmitPipe.Reader.AdvanceTo(buffer.End);
await _stream.FlushAsync(_cts);
}
}
catch (Exception e)
{
Console.WriteLine($"DuplexPipe Transmit caught an exception: {e.Message}");
error = e;
}
finally
{
await _transmitPipe.Reader.CompleteAsync(error);
}
}
}

So, I spent some more time searching around the internet and found something that sort of solves my problem. I found, among some other things, this question: How to handle incoming TCP messages with a Kestrel ConnectionHandler?
Here it seems like the ConnectionHandler class provides exactly what I need, including some very handy plumbing for handling SSL certificates, port listening, etc that comes for free when building an ASP.NET application.

Related

Should I queue a Nmodbus4 RTU connection by Mutex?

I use library NModbus4 and create RTU connection.
public static IModbusSerialMaster Master { get; set; }
Master = ModbusSerialMaster.CreateRtu(SerialPort);
I have method GetClient()which return Master and Method Registers() which look like:
public static ushort[] Registers(Func<IModbusSerialMaster, ushort[]> action)
{
ushort[] registers = new ushort[0];
var client = GetClient();
if (client == null)
return registers;
//mutex.WaitOne();
try
{
registers = action.Invoke(client);
}
catch (Exception e)
{
log.Error("error");
}
finally
{
//mutex.ReleaseMutex();
}
return registers;
}
I was trying to use System.Threading.Mutexto be sure that only one method will send frames at a time. But after about minute when In loop are run 2/3 task it locks on mutex.WaitOne(); and stop program.
If I not using mutex. I do not see any mistakes. Does NModbus itself ensure that the program does not crash in this way? Or I should find why is this happening, leave a mutex and fix the error?

Handling exceptions thrown when an Akka.NET Actor responds to an async request from a stream

When integrating an actor with an Akka.NET stream as described in the Akka.NET integration docs I hit a problem with exception handling. If the actor just throws an exception then Akka swallows it, and I have to wait for the timeout to trigger for it to get reported.
I'm inferring that this is because the actor doesn't send a message back to the stream. Taking the old-school approach of using a big try-catch at a thread boundary I can marshall an exception into a message for the sender, which allows it to break through the timeout and carry on.
Example code below. As far as I can tell there's no way I can create a supervisor strategy that'll allow the stream to handle the actor's exception. What's the best pattern for handling this?
// Run app with argument "straightThrow" or "catchAndHandle"
class Bleurgher : ReceiveActor
{
public Bleurgher()
{
Receive<string>(s =>
{
switch (s) {
case "straightThrow":
throw new Exception("Bleurgh");
break;
case "catchAndHandle":
try
{
throw new Exception("Bleurgh");
}
catch (Exception x)
{
Console.WriteLine($"Exception : {x.Message}");
Sender.Tell(new Akka.Actor.Status.Failure(x));
};
break;
}
});
}
public static Akka.Actor.Props Props()
{
return Akka.Actor.Props.Create<Bleurgher>();
}
}
class Program
{
static void Main(string[] args)
{
using (var system = ActorSystem.Create("cast"))
using (var materializer = system.Materializer())
{
var data = new List<string>(args);
var bleurgher = system.ActorOf(Bleurgher.Props());
var source = Source.From(data);
var sink = Sink.ForEach<string>(s => Console.WriteLine(s));
var runnable = source
.SelectAsync(1, o => bleurgher.Ask(o, TimeSpan.FromSeconds(5)))
.Select(o => (o.ToString()))
.ToMaterialized(sink, Keep.Right);
runnable.Run(materializer).Wait();
}
}
}

Detect ongoing write operation on a networkstream

Imagine a server application is connected via TCP to some client device. The user of the server decides to send some message to the client device with NetworkStream.BeginWrite, but due to a slow connection or some other unknown factor, the server calls BeginWrite, but BeginWrite has not yet finished its write and performed its callback. In the meantime, the user decides to disconnect the client device in the main thread, causing an ObjectDisposedException to be immediately thrown in the callback due to the underlying connection no longer being available.
Here's a pseudo example of what I mean:
/// bad pseudo of possible code happening in main server thread
while(!quit){
if( command has been inputted) {
switch (command) {
case send:
string m = getAStringFromGUI();
Send(m);
break;
case disconnect:
ClientDevice.Close();
break;
}
}
}
private void Send(string msg){
NetworkStream stream;
byte[ ] packetBuffer = Encoding.ASCII.GetBytes(msg);
stream = clientDevice.GetStream();
stream.BeginWrite(packetBuffer, 0, packetBuffer.Length, new AsyncCallback(StreamWriteCompleteCallback), stream);
}
private void StreamWriteCompleteCallback(IAsyncResult ar) {
try {
NetworkStream stream = (NetworkStream)ar.AsyncState;
stream.EndWrite(ar);
}
catch (ObjectDisposedException) {
// client device was disconnected by the server before write completed
}
}
If a disconnect command is entered fast enough after the send command, the exception will be thrown. Obviously in this simple example, you could block until the write is complete, but what if you wanted to have the writes to occur asynchronously but still prevent disconnect commands from executing until any write commands have completed (or timed out)? I believe you could keep track of all the BeginWrite calls with waithandles, and utilize those to ensure writes complete before disconnecting, but that seems like a lot of work. Is there any way to know whether any thread is attempting to write to a given network stream?
You need to track manually the request, but it's more easy than you think, a simple concurrent dictionary would be enough for this:
//This class will store ongoing requests and also will be used as the async parameter
public class ExecutingRequest
{
public Guid Id { get; set; }
public NetworkStream Stream { get; set; }
}
//Somewhere in your server class
ConcurrentDictionary<Guid, ExecutingRequest> pendingRequests = new ConcurrentDictionary<Guid, ExecutingRequest>();
private void Send(string msg)
{
NetworkStream stream;
byte[ ] packetBuffer = Encoding.ASCII.GetBytes(msg);
stream = clientDevice.GetStream();
var request = new ExecutingRequest{ Stream = stream, Id = Guid.NewGuid() };
pendingRequests.AddOrUpdate(request.Id, request, (a,b) => request);
stream.BeginWrite(packetBuffer, 0, packetBuffer.Length, new AsyncCallback(StreamWriteCompleteCallback), request);
}
private void StreamWriteCompleteCallback(IAsyncResult ar)
{
try {
ExecutingRequest req = (ExecutingRequest)ar.AsyncState;
pendingRequests.TryRemove(req.Id, out ExecutingRequest dummy);
req.stream.EndWrite(ar);
}
catch (ObjectDisposedException)
{
// client device was disconnected by the server before write completed
}
}
Then, you can check if there is any request running by checking the length of the dictionary.

MVVM Light making an HTTP Get request using Webapi

I am a newbie when it comes to MVVM and Web related technologies. We are currently developing an MVVM client app using the latest MVVMLight framework in Visual Studios 2013. The application uses Microsoft's Webapi (latest version) to get data into our model via HTTP requests. Our code executes up to the point where the HTTP request is made, and we have confirmed that the server is getting the request, gathering up the requested data and returning it as JSON. However the client never sees the response, it just continues to wait for the response. Its almost as though we are seeing an issue that seems to do with threads. Where the request was made on one thread, but the response is being received on another. Here is our code (where the HTTP request is made):
public class DataService : IDataService
{
#region Fields
private HttpClient _client;
private LfActivityDataReturnObject _activityReturnObj;
private AdroServices _adroServices;
private bool _selectedProcssingOptionPosted = false;
private bool _activityDataSuccessfullyRetrieved = false;
private decimal _incomingLFEntryId;
#endregion
#region Constructor
public DataService()
{
try
{
//Get command line arguments
string[] arguments = Environment.GetCommandLineArgs();
for (int i = 1; i < arguments.Length; i++)
{
switch (i)
{
case 1:
{
if (!Decimal.TryParse(arguments[i], out _incomingLFEntryId))
{
_incomingLFEntryId = -1;
}
break;
}
}
}
if (_incomingLFEntryId <= 0)
{
throw new ArgumentException(String.Format("Invalid Activity Shortcut Entry ID: {0}", _incomingLFEntryId));
}
}
catch (Exception e)
{
throw e;
}
}
#endregion
#region Methods
public void GetGeneralInformationModel(Action<GeneralInformationModel, Exception> callback)
{
Exception locException = null;
GeneralInformationModel locGeneralInformationModel = null;
if (_adroServices == null)
{
try
{
//Start the HTTP request
GetActivityDataAsync().Wait();
}
catch (Exception e)
{
locException = e;
}
// change? should be for http success but adro failure
if (_activityDataSuccessfullyRetrieved)
{
_adroServices = new AdroServices(_activityReturnObj);
locGeneralInformationModel = new GeneralInformationModel(_adroServices);
}
else
{
Exception e2 = new Exception("Error retrieving activity data in DataService");
locException = e2;
}
}
else
{
locGeneralInformationModel = new GeneralInformationModel(_adroServices);
}
var item = locGeneralInformationModel;
callback(item, locException);
}
//Get data from the repository via the service layer.
private async Task GetActivityDataAsync()
{
try
{
using (this._client = new HttpClient())
{
_client.BaseAddress = new Uri("http://localhost:52512//");
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Line below is where the app just runs getting no response
HttpResponseMessage caseDataResponse = await _client.GetAsync(string.Format("api/LfUrs/{0}", _incomingLFEntryId));
if (caseDataResponse.IsSuccessStatusCode)
{
_activityReturnObj = await caseDataResponse.Content.ReadAsAsync<LfActivityDataReturnObject>();
if (_activityReturnObj.ReturnCode == 0)
{
_activityDataSuccessfullyRetrieved = true;
}
else
{
_activityDataSuccessfullyRetrieved = false;
}
}
else
{
_activityDataSuccessfullyRetrieved = false;
}
}
}
catch (Exception ex)
{
_activityDataSuccessfullyRetrieved = false;
throw ex;
}
}
We have tried using Fiddler to get more information but Fiddler doesn't seem to be able to reveal any of the details. Also I should mention that we are simulating the server on the local host and as I stated above, we have confirmed the server gets the request and returns the data. My associates and I are starting to think this has something to do with the MVVM Light Framework and the IOC or possibly threading. When we use this same code in a MVVM solution that doesn't use the framework it works. Any help would be sincerely appreciated. Thanks...Mike
I have figured it out. Somehow, in my app.xaml, the Dispatcher.Helper had been moved to the event On_Startup rather than being contained in the class constructor. Additionally I had to move the HTTP stuff into the ADRO services class and make sure it was constructed in the App constructor in app.xaml right after Dispatcher.Helper. But thanks to everyone who participates here on StackOverFlow. This resource is an absolute life-saver. Thanks

How to use UdpClient.BeginReceive in a loop

I want to do this
for (int i = 0; i < 100; i++ )
{
Byte[] receiveBytes = receivingUdpClient.Receive(ref RemoteIpEndPoint);
}
But instead of using UdpClient.Receive, I have to use UdpClient.BeginReceive. The problem is, how do I do that? There aren't a lot of samples using BeginReceive, and the MSDN example is not helping at all. Should I use BeginReceive, or just create it under a separate thread?
I consistently get ObjectDisposedException exception. I only get the first data sent. The next data will throw exception.
public class UdpReceiver
{
private UdpClient _client;
public System.Net.Sockets.UdpClient Client
{
get { return _client; }
set { _client = value; }
}
private IPEndPoint _endPoint;
public System.Net.IPEndPoint EndPoint
{
get { return _endPoint; }
set { _endPoint = value; }
}
private int _packetCount;
public int PacketCount
{
get { return _packetCount; }
set { _packetCount = value; }
}
private string _buffers;
public string Buffers
{
get { return _buffers; }
set { _buffers = value; }
}
private Int32 _counter;
public System.Int32 Counter
{
get { return _counter; }
set { _counter = value; }
}
private Int32 _maxTransmission;
public System.Int32 MaxTransmission
{
get { return _maxTransmission; }
set { _maxTransmission = value; }
}
public UdpReceiver(UdpClient udpClient, IPEndPoint ipEndPoint, string buffers, Int32 counter, Int32 maxTransmission)
{
_client = udpClient;
_endPoint = ipEndPoint;
_buffers = buffers;
_counter = counter;
_maxTransmission = maxTransmission;
}
public void StartReceive()
{
_packetCount = 0;
_client.BeginReceive(new AsyncCallback(Callback), null);
}
private void Callback(IAsyncResult result)
{
try
{
byte[] buffer = _client.EndReceive(result, ref _endPoint);
// Process buffer
MainWindow.Log(Encoding.ASCII.GetString(buffer));
_packetCount += 1;
if (_packetCount < _maxTransmission)
{
_client.BeginReceive(new AsyncCallback(Callback), null);
}
}
catch (ObjectDisposedException ex)
{
MainWindow.Log(ex.ToString());
}
catch (SocketException ex)
{
MainWindow.Log(ex.ToString());
}
catch (System.Exception ex)
{
MainWindow.Log(ex.ToString());
}
}
}
What gives?
By the way, the general idea is:
Create tcpclient manager.
Start sending/receiving data using udpclient.
When all data has been sent, tcpclient manager will signal receiver that all data has been sent, and udpclient connection should be closed.
It would seem that UdpClient.BeginReceive() and UdpClient.EndReceive() are not well implemented/understood. And certainly compared to how the TcpListener is implemented, are a lot harder to use.
There are several things that you can do to make using the UdpClient.Receive() work better for you. Firstly, setting timeouts on the underlying socket Client will enable control to fall through (to an exception), allowing the flow of control to continue or be looped as you like. Secondly, by creating the UDP listener on a new thread (the creation of which I haven't shown), you can avoid the semi-blocking effect of the UdpClient.Receive() function and you can effectively abort that thread later if you do it correctly.
The code below is in three parts. The first and last parts should be in your main loop at the entry and exit points respectively. The second part should be in the new thread that you created.
A simple example:
// Define this globally, on your main thread
UdpClient listener = null;
// ...
// ...
// Create a new thread and run this code:
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 9999);
byte[] data = new byte[0];
string message = "";
listener.Client.SendTimeout = 5000;
listener.Client.ReceiveTimeout = 5000;
listener = new UdpClient(endPoint);
while(true)
{
try
{
data = listener.Receive(ref endPoint);
message = Encoding.ASCII.GetString(data);
}
catch(System.Net.Socket.SocketException ex)
{
if (ex.ErrorCode != 10060)
{
// Handle the error. 10060 is a timeout error, which is expected.
}
}
// Do something else here.
// ...
//
// If your process is eating CPU, you may want to sleep briefly
// System.Threading.Thread.Sleep(10);
}
// ...
// ...
// Back on your main thread, when it's exiting, run this code
// in order to completely kill off the UDP thread you created above:
listener.Close();
thread.Close();
thread.Abort();
thread.Join(5000);
thread = null;
In addition to all this, you can also check UdpClient.Available > 0 in order to determine if any UDP requests are queued prior to executing UdpClient.Receive() - this completely removes the blocking aspect. I do suggest that you try this with caution as this behaviour does not appear in the Microsoft documentation, but does seem to work.
Note:
The MSDN exmaple code you may have found while researching this problem requires an additional user defined class - UdpState. This is not a .NET library class. This seems to confuse a lot of people when they are researching this problem.
The timeouts do not strictly have to be set to enable your app to exit completely, but they will allow you to do other things in that loop instead of blocking forever.
The listener.Close() command is important because it forces the UdpClient to throw an exception and exit the loop, allowing Thread.Abort() to get handled. Without this you may not be able to kill off the listener thread properly until it times out or a UDP packet is received causing the code to continue past the UdpClient.Receive() block.
Just to add to this priceless answer, here's a working and tested code fragment. (Here in a Unity3D context but of course for any c#.)
// minmal flawless UDP listener per PretorianNZ
using System.Collections;
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
void Start()
{
listenThread = new Thread (new ThreadStart (SimplestReceiver));
listenThread.Start();
}
private Thread listenThread;
private UdpClient listenClient;
private void SimplestReceiver()
{
Debug.Log(",,,,,,,,,,,, Overall listener thread started.");
IPEndPoint listenEndPoint = new IPEndPoint(IPAddress.Any, 1260);
listenClient = new UdpClient(listenEndPoint);
Debug.Log(",,,,,,,,,,,, listen client started.");
while(true)
{
Debug.Log(",,,,, listen client listening");
try
{
Byte[] data = listenClient.Receive(ref listenEndPoint);
string message = Encoding.ASCII.GetString(data);
Debug.Log("Listener heard: " +message);
}
catch( SocketException ex)
{
if (ex.ErrorCode != 10060)
Debug.Log("a more serious error " +ex.ErrorCode);
else
Debug.Log("expected timeout error");
}
Thread.Sleep(10); // tune for your situation, can usually be omitted
}
}
void OnDestroy() { CleanUp(); }
void OnDisable() { CleanUp(); }
// be certain to catch ALL possibilities of exit in your environment,
// or else the thread will typically live on beyond the app quitting.
void CleanUp()
{
Debug.Log ("Cleanup for listener...");
// note, consider carefully that it may not be running
listenClient.Close();
Debug.Log(",,,,, listen client correctly stopped");
listenThread.Abort();
listenThread.Join(5000);
listenThread = null;
Debug.Log(",,,,, listener thread correctly stopped");
}
I think you should not use it in a loop but instead whenever the BeginReceive callback is called you call BeginReceive once more and you keep a public variable for count if you want to limit the number to 100.
have look at MSDN first. They provide good example.
http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.beginreceive.aspx
I would do network communication on a background thread, so that it doesn't block anything else in your application.
The issue with BeginReceive is that you must call EndReceive at some point (otherwise you have wait handles just sitting around) - and calling EndReceive will block until the receive is finished. This is why it is easier to just put the communication on another thread.
You have to do network operations, file manipulations and such things that are dependent to other things rather than your own program on another thread (or task) because they may freeze your program. The reason for that is that your code executes sequentially.
You have used it in a loop which is not fine. Whenever BeginRecieve callback is invoked you should call it again. Take a look at the following code:
public static bool messageReceived = false;
public static void ReceiveCallback(IAsyncResult ar)
{
UdpClient u = (UdpClient)((UdpState)(ar.AsyncState)).u;
IPEndPoint e = (IPEndPoint)((UdpState)(ar.AsyncState)).e;
Byte[] receiveBytes = u.EndReceive(ar, ref e);
string receiveString = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine("Received: {0}", receiveString);
messageReceived = true;
}
public static void ReceiveMessages()
{
// Receive a message and write it to the console.
IPEndPoint e = new IPEndPoint(IPAddress.Any, listenPort);
UdpClient u = new UdpClient(e);
UdpState s = new UdpState();
s.e = e;
s.u = u;
Console.WriteLine("listening for messages");
u.BeginReceive(new AsyncCallback(ReceiveCallback), s);
// Do some work while we wait for a message. For this example,
// we'll just sleep
while (!messageReceived)
{
Thread.Sleep(100);
}
}

Categories