I've created a Gist with my NetMQ implementation as I feel it a bit much to paste here: https://gist.github.com/gthvidsten/e626d7e6c51012b1ba152d22e034d93d
If I do the following in a .Net Core console app, everything works fine and I receive the MessageReceived event:
static void Main(string[] args)
{
_transportWithHost = new NetMqTransport(
"tcp://localhost:9990",
"tcp://localhost:9991",
true);
_transportWithHost.Start();
Console.WriteLine("Press [Enter] to publish");
Console.ReadLine();
_transportWithHost.MessageReceived += (sender, e) =>
{
; // Breakpoints here are hit
};
_transportWithHost.Publish(new byte[] { 1, 2, 3, 4 });
Console.WriteLine("Press [Enter] to exit");
Console.ReadLine();
}
However, if I try to do the same in an NUnit test environment, the MessageReceived event is never fired!
class NetMqTransportTests
{
private NetMqTransport _transportWithHost;
[OneTimeSetUp]
public void Setup()
{
_transportWithHost = new NetMqTransport(
"tcp://localhost:9990",
"tcp://localhost:9991",
true);
_transportWithHost.Start();
}
[Test]
public void PublishTest()
{
ManualResetEvent mre = new ManualResetEvent(false);
_transportWithHost.MessageReceived += (sender, e) =>
{
mre.Set();
// Breakpoints here are never hit as MessageReceived is never called
};
_transportWithHost.Publish(new byte[] { 1, 2, 3, 4 });
bool eventFired = mre.WaitOne(new TimeSpan(0, 0, 5));
Assert.True(eventFired);
}
}
Why does the virtually identical code work in a console app, but not in an NUnit environment?
I was able to reproduce it and found this thread https://github.com/zeromq/netmq/issues/482 which indicates its a timing issue between starting the Publisher and time for the Subscriber to receive the message.
using NetMQ;
using NetMQ.Sockets;
using NUnit.Framework;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Tests
{
class NetMqTransportTests
{
[Test]
public void TestMulticastNetMQ()
{
bool wasCalled = false;
var coreEventbus = "tcp://localhost:12345";
Task.Run(() =>
{
using (var subSocket = new SubscriberSocket())
{
subSocket.Connect(coreEventbus);
subSocket.Subscribe("account");
while (true)
{
string messageTopicReceived = subSocket.ReceiveFrameString();
string messageReceived = subSocket.ReceiveFrameString();
Assert.IsTrue(messageReceived == "testing");
wasCalled = true;
break;
}
}
});
Thread.Sleep(TimeSpan.FromSeconds(1));
using (var pubSocket = new PublisherSocket())
{
pubSocket.Bind(coreEventbus);
Thread.Sleep(500);
pubSocket.SendMoreFrame("account").SendFrame("testing");
}
Thread.Sleep(TimeSpan.FromSeconds(5));
Assert.IsTrue(wasCalled);
}
}
}
Update:
Here are the Unit Tests that come with the NetMQ library: https://github.com/zeromq/netmq/blob/master/src/NetMQ.Tests/XPubSubTests.cs
See how they break up instantiating NetMqTransport into using both XPublisherSocket and XPublisherSocket...
Also notice as per the issue 482 they do a 500ms delay to let the subscriber connect before receiving the message, just like they were talking about in the issue:
[Fact]
public void TopicPubSub()
{
using (var pub = new XPublisherSocket())
using (var sub = new XPublisherSocket())
{
var port = pub.BindRandomPort("tcp://127.0.0.1");
sub.Connect("tcp://127.0.0.1:" + port);
sub.SendFrame(new byte[] { 1, (byte)'A' });
// let the subscriber connect to the publisher before sending a message
Thread.Sleep(500);
var msg = pub.ReceiveFrameBytes();
Related
I'm trying to port my code from an obsolete library called CastleMQ to NetMQ but I'm running into some problems.
I prefer to using polling with a timeout, for reliability - I just found that it worked best for me from trial and error compared to just sitting blocking the port indefinitely.
here is my CastleMQ code
public int ZeroPort;
private void ThreadProc()
{
var ctx = new Context();
try {
using (var repSocket = ctx.CreateSocket(SocketType.Rep))
{
string bindAddress = "tcp://*:"+ZeroPort;
repSocket.Bind(bindAddress);
print2("*** BINDING on {0} ***", bindAddress);
bool quit = false;
while (!quit) {
try {
var polling = new Polling(PollingEvents.RecvReady, repSocket);
polling.RecvReady += (socket) =>
{ // using socket.Recv() here is guaranted to return stuff
var msg = socket.Recv();
var msgStr = Encoding.UTF8.GetString(msg);
print2("[REP:{0}] {1}", bindAddress, msgStr);
switch (msgStr) {
case "positions": {
StringBuilder csv = new StringBuilder();
print2("csv: {0}", csv.ToString());
socket.Send(csv.ToString());
break;
}
default: {
socket.Send("Unrecognized Command: " + msgStr);
break;
}
}
};
polling.Poll(POLL_TIMEOUT_MS); // this returns once some socket event happens
} catch (Exception e) {
if (e is ThreadAbortException) {
quit = true;
print2("\n*** EXITED ***");
} else print2(e.ToString());
}
}
}
} catch (Exception e) {
print2(e.ToString());
} finally {
ctx.Dispose();
}
}
here is what I tried to do and then got lost with NetMQ
private void ThreadProc()
{
try {
string bindAddress = "#tcp://*:" + ZeroPort;
print2("*** BINDING on {0} ***", bindAddress);
using (var repSocket = new ResponseSocket(bindAddress))
using (var poller = new NetMQPoller { repSocket })
{
// bool quit = false;
// while (!quit)
// these event will be raised by the Poller
repSocket.ReceiveReady += (s, a) =>
{
// receive won't block as a message is ready
string msg = a.Socket.ReceiveString(); // defeinition for ReceiveString() can't be found
// send a response
a.Socket.Send("Response"); // it doesn't like "Response", do I need to wrap it in some object?
I'm especially confused as how to add a timeout so I can poll with a timeout in a loop the way my CastleMQ code does.
Any pointers would be much appreciated, thanks
This is a TCP Program which receives data from a TCP connection, then parse it and transfer it to another TCP connection. When I exit application, it doesn't work. It will remain as a process in the system.
As I am not a very experienced developer, can someone please help me to find the error in this code..
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
namespace Machine_Feeder
{
public partial class FeederControlMonitor : Form
{
TcpListener Listener = null;
public string Status = string.Empty;
public Thread T = null;
public FeederControlMonitor()
{
InitializeComponent();
}
private void FeederControlMonitor_Load(object sender, EventArgs e)
{
txtStatus.Text = "Feeder waiting for data...";
ThreadStart Ts = new ThreadStart(StartReceiving);
T = new Thread(Ts);
T.Start();
}
public void StartReceiving()
{
ReceiveTCP(9100);
}
public void ReceiveTCP(int portN)
{
try
{
Listener = new TcpListener(IPAddress.Any, portN);
Listener.Start();
}
catch (Exception ex)
{
File.WriteAllText(#"C:\\Drive\\ex.txt", ex.Message);
Console.WriteLine(ex.Message);
}
try
{
while (true)
{
Socket client = Listener.AcceptSocket();
var childSocketThread = new Thread(() =>
{
byte[] data = new byte[10000];
int size = client.Receive(data);
ParseData(System.Text.Encoding.Default.GetString(data));
client.Close();
});
childSocketThread.Start();
}
Listener.Stop();
}
catch (Exception ex)
{
File.WriteAllText(#"C:\\Drive\\ex.txt", ex.Message);
}
}
public void ParseData(string data)
{
var useFulData = data.Substring(data.IndexOf("F1")).Replace(" ", " ");// Space
useFulData = useFulData.Remove(useFulData.IndexOf("<ETX>"));
string[] delimeters = { "<DEL>", "<ESC>" };
var listOfValues = useFulData.Split(delimeters, StringSplitOptions.None).ToList();
int pos = 0;
for (int i = 1; i < listOfValues.Count; i += 2, pos++)
{
listOfValues[pos] = listOfValues[i];
}
listOfValues.RemoveRange(pos, listOfValues.Count - pos);
txtHealthCard.Invoke((Action)delegate { txtHealthCard.Text = listOfValues[0]; });
txtCID.Invoke((Action)delegate { txtCID.Text = listOfValues[1]; });
txtMedicalFitLocation.Invoke((Action)delegate { txtMedicalFitLocation.Text = listOfValues[2]; });
txtGender.Invoke((Action)delegate { txtGender.Text = listOfValues[3]; });
txtAge.Invoke((Action)delegate { txtAge.Text = listOfValues[4]; });
txtPatientName.Invoke((Action)delegate { txtPatientName.Text = listOfValues[5]; });
MyProtocolMaker(listOfValues[5],
listOfValues[4],
listOfValues[2],
listOfValues[3],
listOfValues[8],
listOfValues[1],
listOfValues[10],
);
}
private void btnExit_Click(object sender, EventArgs e)
{
Listener.Stop();
T.Abort();
this.Close();
}
private void MyProtocolMaker(
string patientName,
string patientAge,
string mfitLocation,
string gender,
string healthCardNo,
)
{
string feederInfo = "^^^P^PI" + healthCardNo + "^PN" + patientName + "^PA" + patientAge + "^PS" + gender + "^P7" + mfitLocation +"^_SS^^^_S";
System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient("127.0.0.1", 8001);
NetworkStream serverStream = clientSocket.GetStream();
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(feederInfo);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
serverStream.Close();
clientSocket.Close();
}
private void FeederControlMonitor_FormClosing(object sender, FormClosingEventArgs e)
{
Listener.Stop();
T.Abort();
this.Close();
}
}
}
You problem is, that you are creating threads within the thread. These threads are keeping the application alive. Try marking them as background threads: (This is red-tape solution)
var childSocketThread = new Thread(() =>
{
byte[] data = new byte[10000];
int size = client.Receive(data); // <-- the thread hangs on these and will block termination
ParseData(System.Text.Encoding.Default.GetString(data));
client.Close();
});
childSocketThread.IsBackground = true; // <---
childSocketThread.Start();
When thread are not marked as background (default), they will block application termination. You should create a list to store the client threads, so you can exit those threads nicely.
You should never abort a thread, unless there is no other way. Instead of aborting, you should exit the while loop in the thread.
As nice way is using a ManualResetEvent:
fields:
private ManualResetEvent _terminating = new ManualResetEvent(false);
in thread:
while (_terminating.WaitOne(0))
{
// thread code
}
on exit:
_terminating.Set();
T.Join();
Sidenote: TCP is streaming, so just reading 10k of bytes ones, does not guarantee a complete packet.
I'm trying to create a simple game using the XNA Framework. I'm starting to implement multiplayer over LAN. Everything has been going well but now I'm running into a problem with UDPClient.Receive.
When the server is running, it is supposed to have two listeners(using UDPClient.Receive), on different ports. One listener is waiting for any incoming connection requests for people who want to join the game and respond accordingly. The other listens for constant updates on the player's positions so it can keep all players' views synchronised. The problem is that I don't know how to code in the first listener.
When the listener for connection request starts, all the code freezes, and it doesn't start until that listener will receive something. How would I code it so it is just running in the background?
Here is my code for the connection listener:
public class Connect
{
public static void WaitForConnections()
{
UdpClient udpc2 = new UdpClient(2054);
IPEndPoint ep = null;
Random rnd = new Random();
Console.WriteLine("Waiting for connections...");
byte[] joinrequest = udpc2.Receive(ref ep);
if (Encoding.ASCII.GetString(joinrequest) == "join")
{
Console.WriteLine("Attempting to join");
if (Server.ConnectedPlayers.Count < Server.MaxPlayers)
{
byte[] newShooter = DataControls.ClassToByteArray(new ShooterObject(Server.ConnectedPlayers.Count + 1, new Vector2(((Server.ConnectedPlayers.Count + 1) * 100) + 22, 70), new byte[3] { (byte)rnd.Next(255), (byte)rnd.Next(255), (byte)rnd.Next(255) }));
udpc2.Send(newShooter, newShooter.Length, ep);
Console.WriteLine("Joined successfully");
}
else
{
byte[] error = Encoding.ASCII.GetBytes("full");
udpc2.Send(error, error.Length, ep);
Console.WriteLine("Too many players");
}
}
}
}
You need to use a background worker thread or equivalent (look at Task and threads generally) but to help you get going in basic full example:
using System;
using System.ComponentModel;
using System.Threading;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main()
{
// Create our listener and start listening...
var sammpleListener = new SampleListener();
sammpleListener.StartListening();
// Run forever...
Console.WriteLine("Waiting for players to join...");
Console.WriteLine("Press Ctrl+C to stop!");
for (var counter = 1;; counter++)
{
Console.WriteLine("Main thread working: {0}...", counter);
Thread.Sleep(200);
}
}
internal class SampleListener
{
private readonly BackgroundWorker _udpWaitForPlayer;
public SampleListener()
{
_udpWaitForPlayer = new BackgroundWorker();
_udpWaitForPlayer.DoWork += _udpWaitForPlayer_DoWork;
}
public void StartListening()
{
_udpWaitForPlayer.RunWorkerAsync();
}
private void _udpWaitForPlayer_DoWork(object sender, DoWorkEventArgs e)
{
const int junkSample = 10;
for (var i = 1; i <= junkSample; i++)
{
// Notice how this doesn't make the main thread sleep / hang...
Console.WriteLine("Background worker working: {0} of {1}...", i, junkSample);
Thread.Sleep(1000);
}
Console.WriteLine("Background worker: Finished!");
}
}
}
}
In my following code, the Timer_Elapsed event is not hitting.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using System.Reflection;
using System.Diagnostics;
namespace Logger
{
internal class Country
{
public string CountryName { get; set; }
public string CountryCode { get; set; }
}
internal class CountryLogger
{
List<Country> countries = new List<Country>()
{
new Country{CountryName = "India", CountryCode="IND"},
new Country{CountryName = "United States of America", CountryCode="USA"},
new Country{CountryName = "United Kingdom", CountryCode="UK"},
new Country{CountryName = "Australia", CountryCode="AUS"}
};
public void WriteToLog()
{
string fileName = #"C:\ParallelLog.txt";
using (StreamWriter writer = new StreamWriter(fileName, true))
{
foreach (Country Country in countries.AsParallel().AsOrdered())
{
writer.WriteLine("{0} - {1}", Country.CountryName, Country.Count ryCode);
writer.WriteLine();
}
}
}
}
internal class Program
{
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Enabled = true;
timer.Interval = 3 * 60 * 1000;
timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
}
static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//for (int i = 0; i < 10; i++)
//{
Task task = Task.Factory.StartNew(() =>
{
CountryLogger countriesLogger = new CountryLogger();
countriesLogger.WriteToLog();
});
//}
}
}
}
Also the Task task = Task.Factory.StartNew(() => object is not looping through the for loop (Commented because it doesn't work).
Can someone suggest the better way of writing this code to work?!
What should the first program thread do whilst letting the timer run?
Here, I'm just waiting for the user to hit return:
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
timer.Interval = 3 * 60 * 1000;
timer.Enabled = true;
Console.WriteLine("Press return to exit");
Console.ReadLine();
GC.KeepAlive(timer); //Can't decide if this is needed or not
}
What is important is that if you return from Main (or just hit that final }), your program is going to exit. I can't remember whether timers keep themselves alive in terms of Garbage Collection, so I've added a GC.KeepAlive just in case.
I've also switched around the order of assignments on the timer - so that it's not enabled until I know that the handler is attached and that the interval is set correctly.
I have a big problem, but probably it's only big for me :). "terminal.Bind(client);" this line causes my program to hang if IP is bad. I want to stop this program after 5s working because if IP is wrong after 10s all program is hang.. :(
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rebex.TerminalEmulation;
using Rebex.Security;
using Rebex.Net;
namespace Routers_info_v._1
{
class Program
{
static void Main(string[] args)
{
Telnet client = new Telnet("192.168.1.1");
VirtualTerminal terminal = new VirtualTerminal(80, 25);
terminal.Bind(client);
terminal.SendToServer("pass\r");
terminal.SendToServer("sys ver\r");
TerminalState state;
do
{
state = terminal.Process(2000);
} while (state == TerminalState.DataReceived);
terminal.Save("terminal.txt", TerminalCaptureFormat.Text, TerminalCaptureOptions.DoNotHideCursor);
terminal.Unbind();
terminal.Dispose();
}
}
}
Try to wrap the call in a try catch (assuming some exception is thrown):
try
{
terminal.Bind(client);
}
catch(Exception ex)
{
return;
}
You could kick off the Bind in a thread, and start a timer, if the thread takes X seconds too long to complete, you could kill the thread, or your application, whichever you choose.
You can use Task.Wait. Here is little simulation for an operation which will take 10 sec and you are waiting it for 5 sec to finish :)
using System;
using System.Linq;
using System.Data.Linq;
using System.Data;
using System.Threading.Tasks;
namespace ConsoleApplication5
{
class VirtualTerminal
{
public VirtualTerminal(int a, int b) { }
public bool Bind() { System.Threading.Thread.Sleep(10000); return true; }
}
class Program
{
static void Main(string[] args)
{
VirtualTerminal terminal = new VirtualTerminal(80, 25);
Func<bool> func = () => terminal.Bind() ;
Task<bool> task = new Task<bool>(func);
task.Start();
if (task.Wait(5*1000))
{
// you got connected
}
else
{
//failed to connect
}
Console.ReadLine();
}
}
}
I would suggest to put the network stuff into a second thread, which then may be aborted by the main thread.
class Program {
static void Main(string[] args) {
Thread thread = new Thread(threadFunc);
thread.Start();
Stopwatch watch = new Stopwatch();
watch.Start();
while (watch.ElapsedMilliseconds < 5000 && thread.IsAlive)
;
if (!thread.IsAlive) {
thread.Abort();
Console.WriteLine("Unable to connect");
}
}
private static void threadFunc() {
Telnet client = new Telnet("192.168.1.1");
VirtualTerminal terminal = new VirtualTerminal(80, 25);
terminal.Bind(client);
// ...
terminal.Dispose();
}
}