NetMQ (ZeroMQ) how to make "Brokerless Reliability (Freelance Pattern)" works - c#

I facing some problems with the example I got from the ZeroMQ Guide, looks like the class ZSocket and ZContext doesn't exist.
I'm totally new with ZeroMQ (just start lo learn) and I'm following the "ØMQ - The Guide". The first example about REQ-REP, which is very simple, worked well. But now I'm trying something more similar to my objective, the "Brokerless Reliability (Freelance Pattern)" and this one didn't work.
I'm using Visual Studio 2019 with C# code, I created a new project, added NetMQ V4.0.1.6 via Nuget and copied the server code to my project. I got errors with ZContext and ZSocket. I already check the API V3 and API V4, they are clear different. The guide is totally based on version 3 and I'm using V 4. I didn't find any document about the changes or updates or equivalent function/classes/methods and I don't know how to convert the example to the NetMQ V4.
This is my test code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using NetMQ;
namespace Examples
{
static partial class Program
{
public static void FLServer1(string[] args)
{
//
// Freelance server - Model 1
// Trivial echo service
//
// Author: metadings
//
if (args == null || args.Length < 1)
{
Console.WriteLine();
Console.WriteLine("Usage: ./{0} FLServer1 [Endpoint]", AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine();
Console.WriteLine(" Endpoint Where FLServer1 should bind on.");
Console.WriteLine(" Default is tcp://127.0.0.1:7780");
Console.WriteLine();
args = new string[] { "tcp://127.0.0.1:7780" };
}
using (var context = new ZContext())
using (var server = new ZSocket(context, ZSocketType.REP))
{
server.Bind(args[0]);
Console.WriteLine("I: echo service is ready at {0}", args[0]);
ZMessage message;
ZError error;
while (true)
{
if (null != (message = server.ReceiveMessage(out error)))
{
using (message)
{
server.Send(message);
}
}
else
{
if (error == ZError.ETERM)
return; // Interrupted
throw new ZException(error);
}
}
}
}
}
}

After long hours trying to understand that logic, I found a list of differences from ZeroMQ V3 and V4:
https://github.com/zeromq/netmq/wiki/Migrating-to-v4
Also, accidentally I found the example I was looking for:
https://github.com/NetMQ/Samples/tree/master/src/Brokerless%20Reliability%20(Freelance%20Pattern)/Model%20One

Related

c# interprocess communication between .net 6 and framwork 4.8

WCF is really easy to make, literally i think 10 lines you can setup the WCF, but just one problem....i did not work in .net 6, i tried, was happy, until i run the app, he compiles with the exact same code from 4.8 but start generating exception after exception
and after some google, it seams that .net 6 (core) did not support WCF anymore
so what is the best way to make a desktop .net framework 4.8 app and a .net 6 WPF app communicate between then, exchanging some flag and variables
the simplest way possible, preferable one unique way that can be implemented in both 4.8 and 6.0, but i don't mind if is different technologies in both end if it works and is simple
I would prefer Interprocess-Communication via NetNamedPipes (NamedPipeServerStream and NamedPipeClientStream) and using Protobuf serialization.
for people suffering with that, abandon WCF if you just wanna send/get simple flags/infos/strings use NamedPipeServerStream and NamedPipeClientStream as #egal_reloaded posted, some (ugly) code samples:
4.8:
server class:
using System;
using System.Collections.Generic;
using System.IO.Pipes;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PipeTetst_FrameWork48_WCF
{
public class NamedPipeStreamServer
{
public void server()
{
var pipeServer = new NamedPipeServerStream("testpipe481", PipeDirection.InOut, 4);
StreamReader sr = new StreamReader(pipeServer);
StreamWriter sw = new StreamWriter(pipeServer);
do
{
try
{
pipeServer.WaitForConnection();
string test;
sw.WriteLine("Waiting");
sw.Flush();
pipeServer.WaitForPipeDrain();
test = sr.ReadLine();
MessageBox.Show(string.Format("Received from client: {0}", test));
}
catch (Exception ex) { throw ex; }
finally
{
pipeServer.WaitForPipeDrain();
if (pipeServer.IsConnected) { pipeServer.Disconnect(); }
}
} while (true);
}
}
}
client class:
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PipeTetst_FrameWork48_WCF
{
public class NamedPipeStreamClient
{
public void client()
{
var pipeClient = new NamedPipeClientStream(".",
"testpipe482", PipeDirection.InOut, PipeOptions.None);
if (pipeClient.IsConnected != true)
{
pipeClient.Connect();
}
StreamReader sr = new StreamReader(pipeClient);
StreamWriter sw = new StreamWriter(pipeClient);
string temp;
temp = sr.ReadLine();
if (temp == "Waiting")
{
try
{
sw.WriteLine("Test Message");
sw.Flush();
pipeClient.Close();
}
catch (Exception ex)
{
throw ex;
}
}
}
}
}
two button on a form in a TASK to not block the app(freeze):
private void button5_Click(object sender, EventArgs e)
{
NamedPipeStreamServer server = new NamedPipeStreamServer();
Task.Run(() => server.server()).ContinueWith(
_ =>
{
MessageBox.Show("asd Server");
}); // Scheduled to the ThreadPool
}
private void button6_Click(object sender, EventArgs e)
{
NamedPipeStreamClient client = new NamedPipeStreamClient();
Task.Run(() => client.client()).ContinueWith(
_ =>
{
MessageBox.Show("asd client");
}); // Scheduled to the ThreadPool
}
and the best part, this code os for .net framwork 4.8 traditional and .net 6 is the exact same code and WORKS!!
of course, you need to have 2 of this code above in 2 app different, and set the name of the pipes right
and the best part NO need to waste days trying to make something broken and unfinished like CoreWCF that need way too much code and is not reliable and only works in some frameworks and in each has a different code, and was almost 0 support they only have a half asset samples on GitHub that don't help with anything

Wireguard tunnel source to c#.Net: Service Run troubleshooting

I'm trying to make a simple console app client (starter.exe) on c# .NET Framework 4.6 to make a WireGuard protocol based connection using Wireguard source code.
What is done:
Downloaded wireguard source code from here: git://git.zx2c4.com/wireguard-windows
Successfuly built Tunnel.dll in ..\embeddable-dll-service\amd64\tunnel.dll via build.bat
Created a project in Visual Studio 2015.using the c# code from ..\embeddable-dll-service\csharp
Starting from here some strange thing are happenning:
if launching starter.exe \service <path to *.conf> I receive the
error
Service run error: The service process could not connect to the
service controller.
if launching starter.exe without parameters everything works fine until I remove the if{} block:
Unhandled Exception: System.ComponentModel.Win32Exception: The service
did not respond to the start or control request in a timely fashion
at WireGuardTunnel.Service.Add(String configFile) in
D:\Depository\BitBucket\WireGuard_Tunnel_Repository\WireGuardTunnel_proj\Launcher\Service.cs:line
69 at WireGuardTunnel.Program.Main(String[] args) in
D:\Depository\BitBucket\WireGuard_Tunnel_Repository\WireGuardTunnel_proj\Launcher\Program.cs:line
83
That means even if the code in if{} block is not executed it influencese somehow the application behaviour.
Next, as I want to make my app work with parameters I solved the
issue by removing return afer Service.Run and passing args[1] to Service.Add(args[1]). It works OK, but I have an extra log line (the first one due to Service.Run perpetual error described above) in the log:
Service run error: The service process could not connect to the
service controller. 235660: [TUN] [chicago4] Watching network
interfaces 245661: [TUN] [chicago4] Resolving DNS names
245661: [TUN] [chicago4] Creating Wintun interface 225660: [TUN]
[chicago4] Starting WireGuard/0.3.1 (Windows 6.1.7601; amd64)
So finally the questions:
Why Service.Run(confFile) does not work
Why Service.Run(confFile) influences the Service.Add(confFile)
Why if{} block is executed when I launch starte.exe with no parameters
The original Program.cs without modification:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.InteropServices;
namespace Tunnel
{
class Program
{
[DllImport("kernel32.dll")]
private static extern bool SetConsoleCtrlHandler(SetConsoleCtrlEventHandler handler, bool add);
private delegate bool SetConsoleCtrlEventHandler(UInt32 signal);
public static void Main(string[] args)
{
string baseDirectory = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
string configFile = Path.Combine(baseDirectory, "demobox.conf");
string logFile = Path.Combine(baseDirectory, "log.bin");
if (args.Length == 2 && args[0] == "/service")
{
configFile = args[1];
Service.Run(configFile);
return;
}
try { File.Delete(logFile); } catch { }
Ringlogger log = new Ringlogger(logFile, "GUI");
var logPrintingThread = new Thread(() =>
{
var cursor = Ringlogger.CursorAll;
while (Thread.CurrentThread.IsAlive)
{
var lines = log.FollowFromCursor(ref cursor);
foreach (var line in lines)
Console.WriteLine(line);
Thread.Sleep(300);
}
});
logPrintingThread.Start();
SetConsoleCtrlHandler(delegate
{
Service.Remove(configFile);
Environment.Exit(0);
return true;
}, true);
try
{
Service.Add(configFile);
logPrintingThread.Join();
}
finally
{
Service.Remove(configFile);
}
}
}
}
Bit late to the party but I was having the exact same issue as above and discovered that in order to get everything working correctly you have to have Tunnel.Service.Run("path to config") defined on application initialization either in your main loop or your constructor then you can run Tunnel.Service.Add("path to config", true) which will create the service and start the VPN connection. It's also good practice to destroy the service on close using Tunnel.Service.Remove("path to config", true) as the service will continue to run and you will still be connected to your VPN until it is stopped manually.

Enumerate UWP MIDI API devices from C# console application?

I want to get a list of installed MIDI Devices in Windows 10, using the Windows 10 UWP MIDI API.
This article shows example code to get a list of MIDI devices and their IDs, using C#:
using Windows.Devices.Midi;
using Windows.Devices.Enumeration;
...
private async void ListMidiDevices()
{
// Enumerate Input devices
var deviceList = DeviceInformation.FindAllAsync(
MidiInPort.GetDeviceSelector());
foreach (var deviceInfo in deviceList)
{
Console.WriteLine(deviceInfo.Id);
Console.WriteLine(deviceInfo.Name);
Console.WriteLine("----------");
}
// Output devices are enumerated the same way, but
// using MidiOutPort.GetDeviceSelector()
}
I tried inserting the code for ListMidiDevices in the Visual Studio Community 2015 "Hello World" example program. I put the code block in place of Console.WriteLine("Hello World!");
in the "hello world" console example. I added the "using" statements above in the proper place.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Midi;
using Windows.Devices.Enumeration;
namespace ConsoleApplicationHelloWorld
{
class Program
{
static void Main(string[] args)
{
// Enumerate Input devices
var deviceList = await DeviceInformation.FindAllAsync(
MidiInPort.GetDeviceSelector());
foreach (var deviceInfo in deviceList)
{
System.Diagnostics.Debug.WriteLine(deviceInfo.Id);
System.Diagnostics.Debug.WriteLine(deviceInfo.Name);
System.Diagnostics.Debug.WriteLine("----------");
}
// Output devices are enumerated the same way, but
// using MidiOutPort.GetDeviceSelector() }
}
}
Edit - VS wasn't building the UWP type. I upgraded to VS Community 2019, and installed ConsoleAppUniversal.vsix. Then I could create a new project - Console App C# Universal:
using System;
using Windows.Devices.Midi;
using Windows.Devices.Enumeration;
// This example code shows how you could implement the required main function for a
// Console UWP Application. You can replace all the code inside Main with your own custom code.
// You should also change the Alias value in the AppExecutionAlias Extension in the
// Package.appxmanifest to a value that you define. To edit this file manually, right-click
// it in Solution Explorer and select View Code, or open it with the XML Editor.
namespace ConsoleAppCsharpUniversal
{
class Program
{
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("starting - no args");
// Enumerate Input devices
var deviceList = DeviceInformation.FindAllAsync(
MidiInPort.GetDeviceSelector());
foreach (var deviceInfo in deviceList)
{
Console.WriteLine(deviceInfo.Id);
Console.WriteLine(deviceInfo.Name);
Console.WriteLine("----------");
}
Console.WriteLine("finish - no args");
}
else
{
for (int i = 0; i < args.Length; i++)
{
Console.WriteLine($"arg[{i}] = {args[i]}");
}
}
Console.WriteLine("Press a key to continue: ");
Console.ReadLine();
}
}
}
Now the only remaining error is "foreach statement cannot operate on variables of type IAsyncOperation<DeviceInformationCollection> because IAsyncOperation<DeviceInformationCollection> does not contain a public instance definition for GetEnumerator"
Is there another way to access the device information without using an async method?
You have to make sure your project is targeting at least C# 7.1 (I think the template does have this out-of-the-box in VS 2019) and use the async Main method feature:
Your method signature will change to:
public static async Task Main(string[] args)
{
...
}
And then you need to await the FindAllAsync method:
var deviceList = await DeviceInformation.FindAllAsync(
MidiInPort.GetDeviceSelector());
Note: You can change the C# version by opening the csproj file in a text editor and adding the following into a <PropertyGroup>:
<LangVersion>7.1</LangVersion>
or even (if you want the latest features):
<LangVersion>latest</LangVersion>

Unable to get all queue names for your WebSphare MQ environment using IBM .Net API

How do you get all available queue names from client side, of your MQ environment using the IBM MQ lib for .Net (IBM.WMQ), Version 8.0?
I have written a fine .Net application for reading and sending data to MQ (similar founds at code project).
Do anyone know if it is possible/how to get all available queue names from the IBM.WMQ .NET lib dynamically as you do when using tool IBM test tool RfhUtil.exe or as you can do with runmqsc DISPLAY QUEUE command from IBM .Net lib?
I have tried to brows the API, Reference manual and IBM programming guide without success.
There is certain level of PCF support in MQ .NET but it is undocumented. Here is a sample code to display queue names in queue manager.
using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using IBM.WMQ;
using IBM.WMQ.PCF;
namespace PCFNET
{
class Program
{
static void Main(string[] args)
{
InquireQueue();
}
/// <summary>
/// Display list of queue names and queue depth for each queue
/// </summary>
public static void InquireQueue()
{
PCFMessageAgent messageAgent = null;
try
{
// Create bindings connection to queue manager
messageAgent = new PCFMessageAgent("DEMOQMGR");
// Build Inquire command to query queue name
PCFMessage reqeuestMessage = new PCFMessage(MQC.MQCMD_INQUIRE_Q);
reqeuestMessage.AddParameter(MQC.MQCA_Q_NAME, "*");
// Send request and receive response
PCFMessage[] pcfResponse = messageAgent.Send(reqeuestMessage);
// Process and print response.
int pcfResponseLen = pcfResponse.Length;
for (int pcfResponseIdx = 0; pcfResponseIdx < pcfResponseLen; pcfResponseIdx++)
{
try
{
String qName = pcfResponse[pcfResponseIdx].GetStringParameterValue(MQC.MQCA_Q_NAME);
int qDepth = pcfResponse[pcfResponseIdx].GetIntParameterValue(MQC.MQIA_CURRENT_Q_DEPTH);
Console.WriteLine("QName: " + qName + " Depth: " + qDepth);
}
catch (PCFException pcfex)
{
//Ignore exception and get the next response
}
}
}
catch (PCFException pcfEx)
{
Console.Write(pcfEx);
}
catch (MQException ex)
{
Console.Write(ex);
}
catch (Exception ex)
{
Console.Write(ex);
}
finally
{
if (messageAgent != null)
messageAgent.Disconnect();
}
}
}
}
There are PCFMessageAgent classes in Java, and I can see some seem to refer to equivalent classes in the .NET API.
It's possible to construct the PCF message yourself, as long as you have rights to access SYSTEM.ADMIN.COMMAND.QUEUE.
You also need to create reply queues dynamically based on SYSTEM.COMMAND.REPLY.MODEL or SYSTEM.MQSC.REPLY.QUEUE.

Sending an LLDP packet using SharpPcap and Packet.Net

So, I spent the afternoon trying to send an LLDP packet in c# using SharpPcap and Packet.Net.
What I came up with bombs with an NullReferenceException. I know why, but I don't know what to do about it.
This is my code:
namespace LLDPTest {
using System;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading;
using PacketDotNet;
using SharpPcap.WinPcap;
class Program {
static void Main(string[] args) {
//var timer = new Timer(state => SendLLDPPacketOnAllInterfaces(), null, 0, 1000);
SendLLDPPacketOnAllInterfaces();
Console.ReadLine();
}
private static void SendLLDPPacketOnAllInterfaces() {
var winPcapDeviceList = WinPcapDeviceList.Instance;
foreach (var device in winPcapDeviceList.Where(device => device.Interface.GatewayAddress != null)) {
SendLLDPPacket(device);
}
}
private static void SendLLDPPacket(WinPcapDevice device) {
var packet = LLDPPacket.RandomPacket();
//packet.Header = ???
var ethernetPacket = new EthernetPacket(device.Addresses[1].Addr.hardwareAddress, PhysicalAddress.Parse("01-80-C2-00-00-0E"), EthernetPacketType.LLDP);
ethernetPacket.PayloadPacket = packet;
device.Open();
device.SendPacket(ethernetPacket);
device.Close();
Console.WriteLine("LLDP packet sent!");
}
}
}
The exception is thrown in in line 36 (device.SendPacket(ethernetPacket);)
The reason for this is that the packet's header property must not be null. The exception is thrown in line 229 of Packet.cs where the following check is performed:
if ((this.header.Bytes != this.payloadPacketOrData.ThePacket.header.Bytes) || ((this.header.Offset + this.header.Length) != this.payloadPacketOrData.ThePacket.header.Offset))
{
return false;
}
Long story short, I simply don't know what I should set the header property to, there are no examples on Google or anywhere else.
EDIT: this.payloadPacketOrData.ThePacket.header is null. This is the packet that results from the call to LLDPPacket.RandomPacket();. Unfortunately the header property has no setter.
EDIT2: I'm using the latest versions of both packets from NuGet.
EDIT3: http://wiki.wireshark.org/LinkLayerDiscoveryProtocol says that
It's interesting to note that unlike the LLDP drafts referenced above,
the final LLDP standard abandoned the notion of an LLDP Header and
instead simply mandated the presence of certain TLVs. In the various
draft documents the LLDP Header was supposed to include a Version
field. The current LLDP standard does not include any notion of a
Version.
Sigh. I have no idea why, but after checking the unit tests (https://github.com/antmicro/Packet.Net/blob/master/Test/PacketType/LldpTest.cs) I stumbled upon the solution (lines 78-79):
var packet = LLDPPacket.RandomPacket();
var lldpBytes = packet.Bytes;
var lldpPacket = new LLDPPacket(new ByteArraySegment(lldpBytes));
I don't know why what the authors call "reparsing" is necessary, but now it works.

Categories