C# how to stop the program after a certain time? - c#

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();
}
}

Related

Why doesn't NetMQ work in an NUnit environment

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();

How to connect to instrument through USB using c#

I am trying to use the Ivi.Visa.Interop .dll to communicate to a Voltech PM1000+ power meter using USB. I'm relatively new to C# and do not know really where to start. I am using Visual Studio 2015 Community. I have already talked to a different instrument using GPIB and here is the code for that:
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 Ivi.Visa.Interop;
namespace commOverIP
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void InitiateIOBtn_Click(object sender, EventArgs e)
{
///testing out excel
InitiateIOBtn.Text = "Initializing";
try
{
// resource manager and message-based session manager
Ivi.Visa.Interop.ResourceManager mngr = new Ivi.Visa.Interop.ResourceManager();
// GPIB address
string srcAddress = "GPIB::27::INSTR"; // GPIB address of data acquisition
//setting up communication
Ivi.Visa.Interop.FormattedIO488 instrument = new Ivi.Visa.Interop.FormattedIO488();
Ivi.Visa.Interop.IMessage Imsg = (mngr.Open(srcAddress, Ivi.Visa.Interop.AccessMode.NO_LOCK, 1000, "") as IMessage);
instrument.IO = Imsg;
instrument.IO.Clear();//clear io buffer
instrument.WriteString("*RST", true);//send RST? command to instrument
instrument.WriteString("*IDN?", true);//send IDN? command to instrument
returnOfCommand.Text = instrument.ReadString();//read IDN? result
//close communication
instrument.IO.Close();
System.Runtime.InteropServices.Marshal.ReleaseComObject(instrument);
System.Runtime.InteropServices.Marshal.ReleaseComObject(mngr);
InitiateIOBtn.Text = "Initialize I/O";
//*/
}
catch(Exception exp)
{
MessageBox.Show(exp.Message);
}
InitiateIOBtn.Text = "Initialize I/O";
}
}
}
This works fine but USB seems to be a different beast. The only real lead I found was in the .dll with the:
IUsb.Init(string, Ivi.Visa.Interop.AccessMode, int, string)
I tried implementing this but I don't really know where to start.
If anyone could give me an example of how to query a "*IDN?" command that would be great. Or, even if there is a better way of doing this than through the Ivi.Visa.Interop dll.
Thanks in advance
Restart your device once. Clearing the IO also helps. Afterwards following code should work fine:
string resourceString= "USB0::xxx::xxx::xxx::0::INSTR";
ResourceManager manager = new ResourceManager();
FormattedIO488 connection = new FormattedIO488();
connection.IO = (IMessage)manager.Open(resourceString, AccessMode.NO_LOCK, 0, "");
connection.IO.Clear();
connection.WriteString("*IDN?", true);
string result = connection.ReadString();
I do what you are asking all of the time and I completely understand how frustrating it can be. I remember doing Google searches to come up with this code. The code actually came from some Keysight documentation when I bought the Agilent 82357B USB/GPIB Controller.
This can be adapted for any GPIB instrument, the only difference being the strings that you send to the instrument. These can be obtained by getting the programming manual for the instrument in which you're interested.
I installed the Keysight (formerly Agilent) I/O Library Suites that is used with the Agilent 82357B. One thing that is not obvious is that you should disable the 'Auto Discovery' option, as this feature will occasionally put your device in Local mode.
using System.Threading;
using System.Runtime.InteropServices;
// Add reference for VISA-COM 5.9 Type Library
using Ivi.Visa.Interop;
namespace USBCommunications
{
class Program
{
static void Main(string[] args)
{
Gpib.Write(address: 5, command: "*IDN?");
bool success = Gpib.Read(address: 5, valueRead: out string valueRead);
System.Console.WriteLine($"The ID is {valueRead}");
System.Console.ReadLine();
}
}
public class Gpib
{
static ResourceManager resourceManager;
static FormattedIO488 ioObject;
public static bool Write(byte address, string command)
{
resourceManager = new ResourceManager();
ioObject = new FormattedIO488();
string addr = $"GPIB::{address.ToString()}::INSTR";
try
{
ioObject.IO = (IMessage)resourceManager.Open(addr, AccessMode.NO_LOCK, 0, "");
Thread.Sleep(20);
ioObject.WriteString(data: command, flushAndEND: true);
return true;
}
catch
{
return false;
}
finally
{
try { ioObject.IO.Close(); }
catch { }
try { Marshal.ReleaseComObject(ioObject); }
catch { }
try { Marshal.ReleaseComObject(resourceManager); }
catch { }
}
}
public static bool Read(byte address, out string valueRead)
{
resourceManager = new ResourceManager();
ioObject = new FormattedIO488();
string addr = $"GPIB::{address.ToString()}::INSTR";
try
{
ioObject.IO = (IMessage)resourceManager.Open(addr, AccessMode.NO_LOCK, 0, "");
Thread.Sleep(20);
valueRead = ioObject.ReadString();
return true;
}
catch
{
valueRead = "";
return false;
}
finally
{
try { ioObject.IO.Close(); }
catch { }
try { Marshal.ReleaseComObject(ioObject); }
catch { }
try { Marshal.ReleaseComObject(resourceManager); }
catch { }
}
}
}
}
Happy programming!!

ClosedXML .SaveAs(MemoryStream ms) does not progress when saving two .xlsm files (each about 7MB) at the same time

To reproduce the issue, I created a console project and below is the code in my Program.cs file:
using System;
using System.IO;
using System.Threading;
using ClosedXML.Excel;
namespace TestSavingTwoBigFiles
{
public class Program
{
private static string folderPath = #"C:\FOLDERPATH\";
private static string fileName1 = folderPath + "FILENAME1.xlsm";
private static string fileName2 = folderPath + "FILENAME2.xlsm";
public static void StartThread(string ordinal, string fileName)
{
Console.WriteLine("Creating {0} file...", ordinal);
var wb = new XLWorkbook(fileName, XLEventTracking.Disabled);
try
{
using (wb)
{
using (var ms = new MemoryStream())
{
Console.WriteLine("Saving {0} file...", ordinal);
wb.SaveAs(ms);
}
}
Console.WriteLine("{0} file saved successfully", ordinal);
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
}
}
public static void Main(string[] args)
{
var thread1 = new Thread(() => StartThread("first", fileName1));
Console.WriteLine("Starting first thread");
thread1.Start();
var thread2 = new Thread(() => StartThread("second", fileName2));
Console.WriteLine("Starting second thread");
thread2.Start();
}
}
}
[Thanks #EmilyLin for the cleaner version]
When I run the above program with two `.xlsm files, one is ~2MB and the other one is ~7MB, the program completes successfully. However, when I run it with two ~7MB files, the program will be stuck at the saving statements and does not progress without throwing an exception. The console will stay as the following image shows and does not change.
One workaround we used was placing a lock on the SaveAs method. Is there a better way?
Thanks!
Placing a lock on the SaveAs method is probably the best way. In the source code for XLWorkbook.cs, both SaveAs functions use FileStream and/or MemoryStream. Neither streams are thread-safe, so your code may not work if run simultaneously with multiple threads, so you should make sure that only one thread can access the MemoryStream at the same time.
Here is an example:
using System;
using System.IO;
using System.Threading;
using ClosedXML.Excel;
namespace Whatever
{
class Class1
{
private static readonly object lockObject = new object();
public static void StartThread(string ordinal, string fileName)
{
Console.WriteLine(string.Format("creating {0} file...", ordinal));
var wb = new XLWorkbook(fileName, XLEventTracking.Disabled);
try
{
using (wb)
using (var ms = new MemoryStream())
{
lock (lockObject)
{
Console.WriteLine(string.Format("saving {0} file...", ordinal));
wb.SaveAs(ms);
}
}
Console.WriteLine(string.Format("{0} file saved successfully", ordinal));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public static void Main(string[] args)
{
var thread1 = new Thread(() => StartThread("first", "a.xlsm"));
thread1.Start();
var thread2 = new Thread(() => StartThread("second", "b.xlsm"));
thread2.Start();
}
}
}

UDPClient.Receive() stops any code from running

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!");
}
}
}
}

Get all IP adresses on LAN

I have a program that ping and take all the ip address that are active in a LAN i code it with csharp console mode the problem is that when I put it in mode form an error appear in Spinwatch and a error message box appear
Here is the code and error below
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.NetworkInformation;
using System.Threading;
namespace pingagediffusiontest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{ }
private static List<Ping> pingers = new List<Ping>();
private static int instances = 0;
private static object #lock = new object();
private static int result = 0;
private static int timeOut = 250;
private static int ttl = 5;
static void Mains()
{
string baseIP = "192.168.1.";
Console.WriteLine("Pinging 255 destinations of D-class in {0}*", baseIP);
CreatePingers(255);
PingOptions po = new PingOptions(ttl, true);
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
byte[] data= enc.GetBytes("abababababababababababababababab");
SpinWait wait = new SpinWait();
int cnt = 1;
Stopwatch watch = Stopwatch.StartNew();
foreach (Ping p in pingers) {
lock (#lock) {
instances += 1;
}
p.SendAsync(string.Concat(baseIP, cnt.ToString()), timeOut, data, po);
cnt += 1;
}
while (instances > 0) {
wait.SpinOnce();
}
watch.Stop();
DestroyPingers();
Console.WriteLine("Finished in {0}. Found {1} active IP-addresses.", watch.Elapsed.ToString(), result);
Console.ReadKey();
}
public static void Ping_completed(object s, PingCompletedEventArgs e)
{
lock (#lock) {
instances -= 1;
}
if (e.Reply.Status == IPStatus.Success) {
Console.WriteLine(string.Concat("Active IP: ", e.Reply.Address.ToString()));
result += 1;
} else {
Console.WriteLine(String.Concat("Non-active IP: ", e.Reply.Address.ToString()))
}
}
private static void CreatePingers(int cnt)
{
for (int i = 1; i <= cnt; i++) {
Ping p = new Ping();
p.PingCompleted += Ping_completed;
pingers.Add(p);
}
}
private static void DestroyPingers()
{
foreach (Ping p in pingers) {
p.PingCompleted -= Ping_completed;
p.Dispose();
}
pingers.Clear();
}
}
}
Error 1 The type or namespace name 'SpinWait' could not be found
Error 3 The type or namespace name 'Stopwatch' could not be found
Error 4 The name 'Stopwatch' does not exist in the current context
Just add the
using System.Diagnostics;
At the top of your file.
Error 3 The type or namespace name 'Stopwatch' could not be found
You need to import following namespace to use StopWatch in your program:
using System.Diagnostics;
as suggested by #CodeCaster in comments - you are missing semicolon to terminate the Console.WriteLine() statement :
Console.WriteLine(String.Concat("Non-active IP: ", e.Reply.Address.ToString())) //missing semicolon
Suggestion : as you have stated you converted code from Console Application to Windows Forms Application it would be nice if you can change/replace all Console.WriteLine() Statements with MessageBox.Show() as shown below:
MessageBox.Show(String.Concat("Non-active IP: ", e.Reply.Address.ToString()));

Categories

Resources