Should I queue a Nmodbus4 RTU connection by Mutex? - c#

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?

Related

Example implementation of IDuplexPipe for a TCP server

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.

Detecting dropped connections

I have a server and many clients. Server needs to know when client disconnects ungracefully (doesn't send TCP FIN), so that it doesn't have hanging connection and other disposable objects associated with this client.
Anyway, I read this and decided to go with adding a "keepalive message to the application protocol" (contains only header bytes) and "explicit timer assuming the worst" methods from the linked blog.
When client connects (btw I am using TcpListener and TcpClient), server starts a System.Threading.Timer that counts down 30 seconds. Whenever server receives something from that client, it resets the timer. When timer reaches 0, it disconnects user and disposes whatever it needs to dispose. Clients application also has a timer and when user doesn't send anything for 15 seconds (half of the server's value, just to be sure), it sends the keepalive message.
My question is, is there easier way to achieve this? Maybe some option on TcpClient? I tried with TcpClient.ReceiveTimeout, but that doesn't seem to work with ReadAsync.
As Stephen points out using heartbeat messages in the application protocol is the only surefire method of ensuring that the connection is alive and that both applications are operating correctly. be warned that many an engineer has created a heartbeat thread that continues to operate even when the application threads have failed.
Using the classes here will solve your asynchronous socket question.
public sealed class SocketAwaitable : INotifyCompletion
{
private readonly static Action SENTINEL = () => { };
internal bool m_wasCompleted;
internal Action m_continuation;
internal SocketAsyncEventArgs m_eventArgs;
public SocketAwaitable(SocketAsyncEventArgs eventArgs)
{
if (eventArgs == null) throw new ArgumentNullException("eventArgs");
m_eventArgs = eventArgs;
eventArgs.Completed += delegate
{
var prev = m_continuation ?? Interlocked.CompareExchange(
ref m_continuation, SENTINEL, null);
if (prev != null) prev();
};
}
internal void Reset()
{
m_wasCompleted = false;
m_continuation = null;
}
public SocketAwaitable GetAwaiter() { return this; }
public bool IsCompleted { get { return m_wasCompleted; } }
public void OnCompleted(Action continuation)
{
if (m_continuation == SENTINEL ||
Interlocked.CompareExchange(
ref m_continuation, continuation, null) == SENTINEL)
{
Task.Run(continuation);
}
}
public void GetResult()
{
if (m_eventArgs.SocketError != SocketError.Success)
throw new SocketException((int)m_eventArgs.SocketError);
}
}

naudio Can't dispose of Asio when using MultiplexingWaveProvider

If I create an AsioOut and use the MultiplexingWaveProvider it works fine (plays / disposes etc..) only if I call AsioOut.Stop() before MultiplexingWaveProvider has run out of data.
If I wait until the MultiplexingWaveProvider has run out of data (and AsioOut has triggered a PlaybackStopped event) I can't Dispose of AsioOut it just hangs and never returns (no error). Note: there is no Dispose() on the MultiplexingWaveProvider, but I've tried calling dispose on the all WaveFileReaders that are used for the MultiplexingWaveProvider.
I've had a couple of people report issues with ASIO drivers when trying to automatically stop. Probably some drivers don't like it if stop is called within the buffer swap callback.
Ideally AsioOut should be updated to offer an option to disable auto stopping. You could simulate this by creating a never-ending ISampleProvider whose Read method returns silence after the end of the source has been reached. Then you could poll to see when the end of your input had been reached, and then Stop and Dispose when its done
This is my implimentaion of Mark's answer. I had to use the IWaveProvidor because the MultiplexingWaveProvider I am using doesn't support the ISampleProvidor. (I could have also implemented a MultiplexingWaveProvider to get the same result I think). Note the task used to not have the stop being called inside the data handler.
public class AsioWavProvidor :IWaveProvider
{
private bool EndSignaled = false;
public Action EndofAudioData;
public Mp3FileReader Mp3Reader;
public AsioWavProvidor(string mp3File)
{
Mp3Reader = new Mp3FileReader(mp3File);
}
public TimeSpan CurrentTime { get { return Mp3Reader.CurrentTime; } }
public int Read(byte[] buffer, int offset, int count)
{
var retCount = Mp3Reader.Read(buffer, offset, count);
if (retCount == 0)
{
if (EndofAudioData != null && !EndSignaled)
{
EndSignaled = true;
System.Threading.Tasks.Task.Run(() =>
{
try
{
EndofAudioData();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
});
}
return count;
}
return retCount;
}

Is it possible to refactor this EventWaitHandle to not use Thread.Sleep() to control the race condition?

I want to send a message from a server to all clients. There are 0-* clients. The server may or may not be running when a client is loaded. The functionality here works how I want it. I am trying to figure out if this can be done without Thread.Sleep()? Also note that the clients and the server are each in independant processes.
Server Portion
class NamedEventsServer
{
internal static void Main()
{
const string ewhName = "StickyNoteEwh";
EventWaitHandle ewh = null;
bool doesNotExist = false;
bool wasCreated;
// Attempt to open the named event.
try
{
ewh = EventWaitHandle.OpenExisting(ewhName);
}
catch (WaitHandleCannotBeOpenedException)
{
Console.WriteLine("Named event does not exist.");
doesNotExist = true;
}
if (doesNotExist)
{
// The event does not exist, so create it.
ewh = new EventWaitHandle(true,
EventResetMode.ManualReset,
ewhName,
out wasCreated);
if (wasCreated)
{
Console.WriteLine("Created the named event.");
}
else
{
Console.WriteLine("Unable to create the event.");
return;
}
}
ewh.Set();
Thread.Sleep(1000);//wait one second...giving threads enough time to all respond. Then stop triggering the event.
ewh.Reset();
//exit
}
}
Client Portion
class NamedEventsClient
{
internal static void Main()
{
const string ewhName = "StickyNoteEwh";
while (true)
{
EventWaitHandle ewh = null;
bool doesNotExist = false;
bool wasCreated;
// Attempt to open the named event.
try
{
ewh = EventWaitHandle.OpenExisting(ewhName);
}
catch (WaitHandleCannotBeOpenedException)
{
Console.WriteLine("Named event does not exist.");
doesNotExist = true;
}
if (doesNotExist)
{
// The event does not exist, so create it.
ewh = new EventWaitHandle(false,
EventResetMode.ManualReset,
ewhName,
out wasCreated);
if (wasCreated)
{
Console.WriteLine("Created the named event.");
}
else
{
Console.WriteLine("Unable to create the event.");
return;
}
}
Console.WriteLine("Wait on the event.");
ewh.WaitOne();
Console.WriteLine("Event was signaled.");
//Console.WriteLine("Press the Enter key exit.");
Thread.Sleep(1000);
//Console.ReadLine();
}
}
}
I guess it depends whether you're certain all clients are going to get their time-slice within on second. It sounds reasonable, but under extreme stress some clients might miss it. How crucial is that?
Anyway, I think this is exactly the kind of thing you should use ZeroMQ for. It's light-weight, and takes care of all the potential bugs for you.

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