I have an assignment in C# involving automation. My code is mainly based off things I have found online. My current problem is I am trying to read in IP addresses line by line from a CSV file into an array, pinging each object of the array, and appending the object so that each object will read "IP, status(if the ping was successful), response time"
I am trying to use a foreach loop but am running into errors. I am on a Mac so it is using mono. Any help would be appreciated.
(Full assignment below if it helps explain anything)
Starting with a premade C# console application, your application will upon running allow for three commands – start, stop, and exit. The application will, upon first running, ask the user for a CSV file (the user must provide a CSV file). This file will contain web addresses (1 per line) – the professor will supply the initial file.
Your application will be setup with a timer so that every time the timer runs, it pings the provided web addresses, gathering whether the server responds or not and the response time of each server. The timer should run continuously from the point the user types “start” until they type “stop” or “exit”. The data will be recorded back to another CSV file, containing the web address, response time, and whether or not the server responded at all.
using System;
using System.Timers;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Collections.Generic;
using Microsoft.VisualBasic;
namespace MT_proj4
{
public class Program
{
public static String[] addressArray = File.ReadAllLines("Project04_URLs.csv");
public static string IP;
public bool status;
public string time;
public static void Main()
{
foreach (string s in addressArray)
{
IP = Console.ReadLine();
bool PingHost(string)
{
bool pingable = false;
#pragma warning disable XS0001 // Find APIs marked as TODO in Mono
Ping pinger = new Ping();
#pragma warning restore XS0001 // Find APIs marked as TODO in Mono
try
{
PingReply reply = pinger.Send(IP);
pingable = reply.Status == IPStatus.Success;
}
catch (PingException)
{
return false;
}
for (int i = 0; i < addressArray.Length; i++)
{
addressArray[i] = addressArray[i] + pingable;
}
}
}
}
static void TimerClass()
{
Timer timer = new Timer(5000);
timer.Elapsed += HandleTimer;
timer.Start();
Console.WriteLine("Type 'exit' to close...");
Console.WriteLine("Enter a command...");
while (true)
{
Console.Write("Command: ");
string command = Console.ReadLine();
Console.WriteLine("Command entered: " + command);
if (command.ToLower() == "stop")
timer.Stop();
else if (command.ToLower() == "exit")
break;
}
}
static void HandleTimer(Object source, ElapsedEventArgs e)
{
Console.WriteLine("\nHandler not implemented...");
}
}
I would restructure your solution a bit. The ping code should run its own thread. Remove the timer, and simply block on Console.ReadLine(). If the results are not expected, repeat until you get either stop or exit.
The reason is the ping work and the console processing are on the same thread. These will block.
Try this:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("pinging....until stop command");
Thread pinger = new Thread(DoPinging);
pinger.Start();
while (true)
{
string command = Console.ReadLine();
if (command.ToLower() == "stop")
break;
else if (command.ToLower() == "exit")
break;
Console.WriteLine("Ignoring-> " + command);
}
pinger.Abort();
}
static void DoPinging()
{
// here goes the pinging code
}
}
In your example code, it looks like you want to read input for ping from Console as well, after the line read, if the value doesn't equal the stop commands (stop, exit), put the value into a queue and let the ping code read from the queue.
You mention reading a CSV file for the addresses to ping (but your example code doesn't reference a file). You can take this as a command line argument (string[] passed in main) and do the work for processing the file in the DoPinging method.
If you want me to add more detail to that, please comment below and I will work on that.
Thnx
Matt
Related
I want to connect to an Ingenico iCT250 POS device through a c# package. I am using this one . I followed the instructions on their readme and tried to connect. When I run, after a few seconds the program closes and I got this message.
C:\Users\User\Documents\c#\pos\pos\bin\Debug\net6.0\pos.exe (process 22480) exited with code 0.
I don't understand why I got this exit code. What is happening?
Is the code wrong? Or there are problems with the cable? How can I research a solution?
Or is it connected because I read that "Saying that the Process finished with exit code 0 means that everything worked ok."? But if everything was okay, the posDevice.IsConnected
should have returned either true or false.
I tried also with passing the port only in new POS. But same result.
Here is the code:
class Program
{
public static void Main(string[] args)
{
POS posDevice = new POS("COM4", 115200);
posDevice.Connect();
Console.WriteLine("IsConnected??", posDevice.IsConnected);
}
}
exited with code 0. means that nothing went wrong with your code (in terms of Exceptions).
but there's two logical problems with your code:
1 - you're not actually writing the result of your test, because you didn't include a placeholder in your format.
so try changing it to:
Console.WriteLine("IsConnected?? {0}", posDevice.IsConnected);
2 - after your program is done, it immediately exits - closing the console window, and hiding the output from you.
so add the following to the end of your Main:
Console.ReadLine();
that way, your program waits for your user input before exiting, keeping the console window open for you to read the result.
the code in total:
class Program
{
public static void Main(string[] args)
{
POS posDevice = new POS("COM4", 115200);
posDevice.Connect();
Console.WriteLine("IsConnected?? {0}", posDevice.IsConnected);
Console.ReadLine();
}
}
Try this:
class Program
{
public static void Main(string[] args)
{
POS posDevice = new POS("COM4", 115200);
posDevice.Connect();
if (posDevice.IsConnected)
{
Console.WriteLine("Device is connected");
Console.ReadKey();
}
else
{
Console.WriteLine("Device is not connected");
Console.ReadKey();
}
}
}
And check the other methods in the "POS" class, which may be useful to troubleshoot the connection issues.
As a workaround for a dumb issue, I have a separate application do my SharePoint file syncing that I launch as a separate process and communicate via WriteLine and ReadLine. After the third Sync command, it seems the Process executes it (as evidenced by a separate log file), but my SyncToolMessageHandler is no longer getting alerted to its responses even with forced flushes on the external process. If I run the program myself and send the exact same commands, no issue in the console window. So why do I seem to lose my message handler? The Process handle is still alive and well.
I also see this in my debugger on SyncToolProcess. It shows this before I send the first WriteLine so I'm not sure what it's talking about but maybe it's a clue? I'm establishing the process/callbacks and sending commands from an "Update" loop in Unity and the responses are obviously asynchronous whenever the process responds. Is that somehow a problem?
Sender:
public void LaunchSyncTool()
{
SyncToolProcess = new Process();
SyncToolProcess.StartInfo.FileName = "SyncProcess.exe";
SyncToolProcess.StartInfo.Arguments = SpecialArguments;
SyncToolProcess.StartInfo.UseShellExecute = false;
SyncToolProcess.StartInfo.RedirectStandardOutput = true;
SyncToolProcess.StartInfo.RedirectStandardInput = true;
SyncToolProcess.StartInfo.RedirectStandardError = true;
SyncToolProcess.StartInfo.CreateNoWindow = true;
SyncToolProcess.OutputDataReceived += new DataReceivedEventHandler(SyncToolMessageHandler);
SyncToolProcess.ErrorDataReceived += new DataReceivedEventHandler(SyncToolMessageHandler);
SyncToolProcess.Start();
SyncToolProcess.BeginOutputReadLine();
SyncToolProcess.BeginErrorReadLine();
SyncToolProcess.StandardInput.WriteLine("Sync File1 File2");
}
// Super simplified, but the ping and pong works great until about the 3rd sync.
public void SyncToolMessageHandler(object sender, DataReceivedEventArgs e)
{
if (e.Data == "Good")
{
Debug("Received 'Good', Sending Command");
SyncToolProcess.StandardInput.WriteLine("Sync File3 File4");
}
else Debug(e.Data); // Exceptions come up Null for some reason, but not seeing them here :-\
// SyncToolProcess.HasExited is always false
}
Receiver:
while (true)
{
string inputCmd = await Console.In.ReadLineAsync();
Debug("Received \"" + inputCmd + "\"");
try
{
string[] split = inputCmd.Split(' ');
switch (split[0])
{
case "Sync":
Sync(split);
break;
case "Quit":
Debug("Quitting");
return;
default:
Debug("Unknown Request: " + inputCmd);
break;
}
}
catch (Exception e)
{
Error(e.Message + "\n" + e.StackTrace);
}
Status("Good");
}
Ugh. The problem was the Unity Editor. If I build the program first it no longer misses the callbacks. Not exactly an answer for using the Editor, but at least I know the code is right!
I just started doing nnanomsg programming with C#. For a simplistic client / server example, I'm starting with the following example where a client connects with a server to get the next number. For now, the example is for localhost, except I have my network IP address hardcoded just to make sure that works. There would be potentially many clients connecting to the server, however this example accesses the server far more aggressively than it would be in real life.
Client Code:
using NNanomsg.Protocols;
using System;
using System.Text;
using System.Threading;
namespace Client {
class Program {
static void Main(string[] args) {
string connect = "tcp://127.0.1.107:9595";
while (true) {
PairSocket s = new PairSocket();
s.Connect(connect);
s.Send(Encoding.UTF8.GetBytes("Hello!"));
Console.WriteLine("Sent");
byte[] ss = null;
while (ss == null) {
ss = s.ReceiveImmediate();
Thread.Sleep(250);
}
s.Dispose();
Console.WriteLine("Received: " + Encoding.UTF8.GetString(ss));
} } } }
Server code:
using System;
using System.Text;
using NNanomsg.Protocols;
namespace Server {
public class Server {
public static int ITER = 0;
public static int NEXT_ID = 10001;
public static string CONNECT;
public static int PORT = 9595;
public static string QUERY;
public static string TCP = "tcp://127.0.1.107";
static void Main(string[] args) {
string bind = TCP + ":" + PORT;
Console.WriteLine("server starting...");
PairSocket s = new PairSocket();
s.Bind(bind);
while (true) {
byte[] ss = null;
ss = s.Receive();
Console.WriteLine("Received from client: " + Encoding.UTF8.GetString(ss));
byte[] b = Encoding.UTF8.GetBytes(NEXT_ID.ToString());
Console.WriteLine("Sent next id " + NEXT_ID);
s.Send(b);
NEXT_ID++;
if (NEXT_ID > 65535) { NEXT_ID = 10001; }
} } } }
In general, this works swimmingly when there is a server and a single client. However, when I start a second client on the same physical machine, they work together for a while, for maybe 5 to 10 iterations, then one of the clients, usually the one which was most recently started, hangs. Adding delays (Thread.sleep(5000) for example) improves the situation slightly, however it will eventually hang after maybe 50 iterations. Currently, the client stops immediately after displaying "Sent". I haven't yet tried starting a client from another physical machine on the network.
Also, whether I wait in a loop with ReceiveImmediate() or just sit at a Receive() does not seem to matter.
What I expect is that every client would have a chance to send the server a request and have a reply. The exact order is not that important, as long as the server eventually responds to a client's request.
I would like to understand why it hangs. I have the latest version of the DLL, 1.1.5.
Thanks very much for every bit of assistance.
Simple solution: I switched over to ZeroMQ. Evidently ZeroMQ handles multiple threads far better.
I've recently started with .Net remoting and I have managed to get working with some simple tutorials such as building a library dll that works as a calculator which the client can access and use(https://www.youtube.com/watch?v=Ve4AQnZ-_H0).
What I'm looking for to understand is how I could access current information that is held on the server. For example if I have this simple part running on the server:
int x = 0;
while (!Console.KeyAvailable)
{
x++;
System.Threading.Thread.Sleep(1000);
Console.WriteLine(x);
}
What I found so far is that the dll built is only returning a static result, such as with the calculator. I'd want to be able to tell how much x is on the server at any given time, through the client.
I don't know if I'm being clear enough but I'll try to explain better if it's needed.
In the following Server implementation demonstrates how you can keep state between calls.
// this gets instantiated by clients over remoting
public class Server:MarshalByRefObject
{
// server wide state
public static int Value;
// state only for this instance (that can be shared with several clients
// depending on its activation model)
private StringBuilder buildup;
// an instance
public Server()
{
buildup = new StringBuilder();
Console.WriteLine("server started");
}
// do something useful
public int DoWork(char ch)
{
Console.WriteLine("server received {0}", ch);
buildup.Append(ch);
return Value;
}
// return all typed chars
public string GetMessage()
{
Console.WriteLine("server GetMessage called") ;
return buildup.ToString();
}
// how long should this instance live
public override object InitializeLifetimeService()
{
// run forever
return null;
}
}
Notice the override InitializeLifetimeService. If you don't control this, your instance will get torn down after 5 minutes.
To use the above class we use the following code to get a listener up and running, including some of your logic. Don't forget to add an reference to the assembly System.Runtime.Remoting.
static void Main(string[] args)
{
// which port
var chn = new HttpChannel(1234);
ChannelServices.RegisterChannel(chn, false);
// Create only ONE Server instance
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(Server), "server", WellKnownObjectMode.Singleton);
Server.Value = 0;
while (!Console.KeyAvailable)
{
Server.Value++;
System.Threading.Thread.Sleep(1000);
Console.WriteLine(Server.Value);
}
}
When this code runs, it should listen on your local box on port 1234 for connections. On first run I had to disable the firewall, allow that port to pass the local firewall.
A client implementation that uses the Server might look like this. Don't forget to add an reference to the assembly System.Runtime.Remoting.
static void Main(string[] args)
{
var chn = new HttpChannel();
ChannelServices.RegisterChannel(chn, false);
RemotingConfiguration.RegisterWellKnownClientType(
typeof(Server),
"http://localhost:1234/server");
Console.WriteLine("Creating server...");
var s = new Server();
Console.WriteLine("type chars, press p to print, press x to stop");
var ch = Console.ReadKey();
while(ch.KeyChar != 'x')
{
switch(ch.KeyChar )
{
case 'p':
Console.WriteLine("msg: {0}", s.GetMessage());
break;
default:
Console.WriteLine("Got value {0} ", s.DoWork(ch.KeyChar));
break;
}
ch = Console.ReadKey();
}
Console.WriteLine("stopped");
}
If you compile and run this your result can look like this:
I'm calling Process.Start, but it blocks the current thread.
pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
// Start process
mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Trace.TraceError("Unable to run process {0}.");
}
Even when the process is closed, the code doesn't respond anymore.
But Process.Start is really supposed to block? What's going on?
(The process start correctly)
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
namespace Test
{
class Test
{
[STAThread]
public static void Main()
{
Thread ServerThread = new Thread(AccepterThread);
ServerThread.Start();
Console.WriteLine (" --- Press ENTER to stop service ---");
while (Console.Read() < 0) { Application.DoEvents(); }
Console.WriteLine("Done.");
}
public static void AccepterThread(object data)
{
bool accepted = false;
while (true) {
if (accepted == false) {
Thread hThread = new Thread(HandlerThread);
accepted = true;
hThread.Start();
} else
Thread.Sleep(100);
}
}
public static void HandlerThread(object data)
{
ProcessStartInfo pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
Console.WriteLine("Starting process.");
// Start process
Process mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Console.WriteLine("Unable to run process.");
}
Console.WriteLine("Still living...");
}
}
}
Console output is:
--- Press ENTER to stop service ---
Starting process.
Found it:
[STAThread]
Makes the Process.Start blocking. I read STAThread and Multithreading, but I cannot link the concepts with Process.Start behavior.
AFAIK, STAThread is required by Windows.Form. How to workaround this problem when using Windows.Form?
News for the hell:
If I rebuild my application, the first time I run application work correctly, but if I stop debugging and restart iy again, the problem araise.
The problem is not raised when application is executed without the debugger.
No, Process.Start doesn't wait for the child process to complete... otherwise you wouldn't be able to use features like redirected I/O.
Sample console app:
using System;
using System.Diagnostics;
public class Test
{
static void Main()
{
Process p = new Process {
StartInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe")
};
p.Start();
Console.WriteLine("See, I'm still running");
}
}
This prints "See, I'm still running" with no problems on my box - what's it doing on your box?
Create a ProcessStartInfo and set UseShellExecute to false (default value is true). Your code should read:
pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
pInfo.UseShellExecute = false;
// Start process
mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Trace.TraceError("Unable to run process {0}.");
}
I had the same issue and starting the executable creating the process directly from the executable file solved the issue.
I was experiencing the same blocking behavior as the original poster in a WinForms app, so I created the console app below to simplify testing this behavior.
Jon Skeet's example uses Notepad, which only takes a few milliseconds to load normally, so a thread block may go unnoticed. I was trying to launch Excel which usually takes a lot longer.
using System;
using System.Diagnostics;
using static System.Console;
using System.Threading;
class Program {
static void Main(string[] args) {
WriteLine("About to start process...");
//Toggle which method is commented out:
//StartWithPath(); //Blocking
//StartWithInfo(); //Blocking
StartInNewThread(); //Not blocking
WriteLine("Process started!");
Read();
}
static void StartWithPath() {
Process.Start(TestPath);
}
static void StartWithInfo() {
var p = new Process { StartInfo = new ProcessStartInfo(TestPath) };
p.Start();
}
static void StartInNewThread() {
var t = new Thread(() => StartWithPath());
t.Start();
}
static string TestPath =
Environment.GetFolderPath(Environment.SpecialFolder.Desktop) +
"\\test.xlsx";
}
Calls to both StartWithPath and StartWithInfo block my thread in a console app. My console does not display "Process Started" until after the Excel splash screen closes and the main window is open.
StartInNewThread will display both messages on the console immediately, while the splash screen for Excel is still open.
We had this problem when launching a .bat script that was on a network drive on a different domain (we have dual trusted domains). I ran a remote C# debugger and sure enough Process.Start() was blocking indefinitely.
When repeating this task interactively in power shell, a security dialog was popping up:
As far as a solution, this was the direction we went. The person that did the work modified domain GPO to accomplish the trust.
Start server via command prompt:
"C:\Program Files (x86)\IIS Express\iisexpress" /path:\Publish /port:8080
This take access to sub-threads of the tree process of OS.
If you want to launch process and then make the process independent on the "launcher" / the originating call:
//Calling process
using (System.Diagnostics.Process ps = new System.Diagnostics.Process())
{
try
{
ps.StartInfo.WorkingDirectory = #"C:\Apps";
ps.StartInfo.FileName = #"C:\Program Files\Microsoft Office\Office14\MSACCESS.EXE"; //command
ps.StartInfo.Arguments = #"C:\Apps\xyz.accdb"; //argument
ps.StartInfo.UseShellExecute = false;
ps.StartInfo.RedirectStandardOutput = false;
ps.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Maximized;
ps.StartInfo.CreateNoWindow = false; //display a windows
ps.Start();
}
catch (Exception ex)
{
MessageBox.Show(string.Format("==> Process error <=={0}" + ex.ToString(), Environment.NewLine));
}
}