Access denied when sending data with UdpClient - c#

I am trying to create a small Application which reads data from the Serial-/Com-Port and broadcasts the data to my network using port 15000.
Everything works fine on Windows and Linux (using Mono) but I get a Socket Exception on macOS with the following message: Access denied
I tried to run my Application with elevated permissions:
sudo mono ./SerialMonitor.exe
But that doesn't work too.
Is there any way to get rid of that exception? And why does it work without any issues on Windows and Linux?
Here is my code:
using System;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace SerialMonitor
{
class MainClass
{
static SerialPort mSerial = new SerialPort();
static String[] mSerialPorts;
static UdpClient mNetwork;
static IPEndPoint mIP;
static String mData = "";
public static void Main(string[] args)
{
mNetwork = new UdpClient();
mIP = new IPEndPoint(IPAddress.Parse("192.168.1.255"), 15000);
mSerialPorts = SerialPort.GetPortNames();
Console.WriteLine("Select a serial port:");
if (mSerialPorts.Length == 0)
{
Console.WriteLine("No serial ports available!");
return;
}
for (int i = 0; i < mSerialPorts.Length; i++)
{
Console.WriteLine(i + 1 + ": " + mSerialPorts[i]);
}
Console.Write("Selection: ");
int selection = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Selected port: " + mSerialPorts[selection - 1]);
mSerial.PortName = mSerialPorts[selection - 1];
mSerial.BaudRate = 9600;
mSerial.NewLine = "\r\n";
mSerial.Open();
mSerial.DiscardInBuffer();
Console.WriteLine("\nData:");
while (true)
{
try
{
MainClass.mData = mSerial.ReadLine();
Console.WriteLine(MainClass.mData);
byte[] bytes = Encoding.ASCII.GetBytes(MainClass.mData);
mNetwork.Send(bytes, bytes.Length, mIP);
}
catch(SocketException ex)
{
Console.WriteLine("\nNETWORK ERROR: " + ex.Message);
Console.Read();
return;
}
catch (Exception ex)
{
Console.WriteLine("\nERROR: " + ex.Message);
Console.Read();
return;
}
}
}
}
}
I am using Visual Studio Community 2017 for Mac
Version 7.1 (build 1297)
Mono 5.2.0.215 (d15-3/da80840) (64-bit)
Project configuration:
.NET Framework 4.6.1
x86

If you want to send broadcast messages across your local subnet (or broadcasts in general) you have to enable broadcasts on your socket with:
mNetwork.EnableBroadcast = true;
Reference:
https://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient(v=vs.110).aspx
http://answers.unity3d.com/questions/248494/socket-exception-access-denied.html

Related

C# Programming Unisource 4100 GPIB DMM

I am trying to read voltage measurements from my Unisource 4100 GPIB DMM. I know I can connect to the device because I get appropriate responses with the commands '*RST' and '*IDN?', however I cannot get any responses with other commands such as 'SYST:ERR?' or 'CONF:VOLT:DC 1000, 0.001'. I have tested out the code I am trying with on the Agilent 34410A and managed to get the responses I want, but not with the Unisource 4100. I am using the NI GPIB-USB-HS controller to interface with. I have included the code below. Should the SCPI commands not work for all GPIB interfaces? What changes would I have to make to elicit a response from the Unisource 4100?
I have included some code for reference:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Text;
using Ivi.Visa.Interop;
namespace CsharpExample
{
class VoltageExample
{
static void Main(string[] args)
{
VoltageExample DmmClass = new VoltageExample(); //Create an instance of this class so we can call functions from Main
Ivi.Visa.Interop.ResourceManager rm = new Ivi.Visa.Interop.ResourceManager(); //Open up a new resource manager
Ivi.Visa.Interop.FormattedIO488 myDmm = new Ivi.Visa.Interop.FormattedIO488(); //Open a new Formatted IO 488 session
try
{
string DutAddr = "GPIB0::12::INSTR"; //String for GPIB
myDmm.IO = (IMessage)rm.Open(DutAddr, AccessMode.NO_LOCK, 10000, ""); //Open up a handle to the DMM with a 2 second timeout
//myDmm.IO.Timeout = 20000;
myDmm.IO.Clear(); //Send a device clear first
myDmm.WriteString("*RST", true); //Reset the device
myDmm.WriteString("*IDN?", true); //Get the IDN string
string IDN = myDmm.ReadString();
Console.WriteLine(IDN); //report the DMM's identity
myDmm.WriteString("*TST?", true); //Get the IDN string
Thread.Sleep(5000);
string TST = myDmm.ReadString();
Console.WriteLine(TST); //report the DMM's identity
myDmm.WriteString("SYST:ERR?", true); //Get the IDN string
string ERR = myDmm.ReadString();
Console.WriteLine(ERR); //report the DMM's identity
myDmm.WriteString("CONF:VOLT:DC 1000, 0.001", true);
DateTime time = DateTime.Now; //Timer to measure the time difference to get all the readings
TimeSpan diff;
Console.WriteLine("Measurement in Volts");
for(int i = 0; i<10; i++){
//Configure for DCV 100V range, 100uV resolution
myDmm.WriteString("READ?", true);
String DCVResult = myDmm.ReadString();
Console.WriteLine("DCV Reading = " + DCVResult); //report the DCV reading
DmmClass.CheckDMMError(myDmm); //Check if the DMM has any errors
Thread.Sleep(1000);
diff = DateTime.Now.Subtract(time);
//diff = DateTime.Now.Subtract(time.AddSeconds(1).AddMilliseconds(20));
Console.WriteLine("\t\t\t" + diff);
}
myDmm.WriteString("CONF:RES 100, MAX", true);
Console.WriteLine("Measurement in Ohms");
for (int i = 0; i < 10; i++)
{
//Configure for res 1000 Ohm range, 100uV resolution
myDmm.WriteString("READ?", true);
String OHMResult = myDmm.ReadString();
Console.WriteLine("Resistance Measurement = " + OHMResult); //report the DCV reading
DmmClass.CheckDMMError(myDmm); //Check if the DMM has any errors
Thread.Sleep(500);
}
}
catch (Exception e)
{
Console.WriteLine("Error occured: " + e.Message);
}
finally
{
//Close out your resources
try { myDmm.IO.Close(); }
catch{}
try{ System.Runtime.InteropServices.Marshal.ReleaseComObject(myDmm);}
catch {}
try{
System.Runtime.InteropServices.Marshal.ReleaseComObject(rm);
}
catch {}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}

Access to the port "COM1" is denied

I have a RFID devices connected to my laptop through Port COM1(Confirmed correct whereby i had using device manager). However, when i run these code in C# language. It give me an exception Access to the port "COM1" is denied. Anyone can help me to solve this problem? Below is my code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO.Ports;
using System.Threading;
namespace Testing1
{
public class Testing1
{
public static SerialPort iSerialPort = new SerialPort();
static int Main()
{
string strException = string.Empty;
string strComPort = "COM1";
int nBaudrate=Convert.ToInt32(9600);
int nRet = OpenCom(strComPort, nBaudrate, out strException);
if (nRet != 0)
{
string strLog = "Connect reader failed, due to: " + strException;
Console.WriteLine(strLog);
//return;
}
else
{
string strLog = "Reader connected " + strComPort + "#" + nBaudrate.ToString();
Console.WriteLine(strLog);
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
iSerialPort.Close();
return 0;
}
public static int OpenCom(string strPort, int nBaudrate, out string strException)
{
strException = string.Empty;
if (iSerialPort.IsOpen)
{
iSerialPort.Close();
}
try
{
iSerialPort.PortName = strPort;
iSerialPort.BaudRate = nBaudrate;
iSerialPort.ReadTimeout = 200;
iSerialPort.DataBits = 8;
iSerialPort.Parity = Parity.None;
iSerialPort.StopBits = StopBits.One;
iSerialPort.Open();
}
catch (System.Exception ex)
{
strException = ex.Message;
return -1;
}
return 0;
}
}
}
This exception can occur when some other program is accessing the COM1 port. Do you have any other program open that uses the RFID device?
You can check what programs use what ports using Portmon.

C# running server on thread using a lot of CPU

I'm trying to write a voting server and client, so you start the program and it displays the voting form and you can vote on various items. For the server part I've got the server running in a separate thread, but it's using a lot of CPU, how do I reduce the amount of CPU it's using?
this is my server:
Form1 main = new Form1();
try
{
IPAddress ipAd = IPAddress.Parse(main.ipAddress); //use local m/c IP address, and use the same in the client
/* Initializes the Listener */
TcpListener myList = new TcpListener(ipAd, 55548);
/* Start Listeneting at the specified port */
myList.Start();
while (true)
{
string message = "";
Socket s = myList.AcceptSocket();
if (main.users.Contains(s.RemoteEndPoint.ToString()) == false)
main.users.Add(s.RemoteEndPoint.ToString());
byte[] b = new byte[500];
int k = s.Receive(b);
for (int i = 0; i < k; i++)
{
message += (Convert.ToString(b[i]));
}
string[] messageArray = message.Split('/');
MessageBox.Show("help");
if (messageArray[0].CompareTo("vote") == 0)
{
if (main.votes.ContainsKey(messageArray[1]) != true) main.votes.Add(messageArray[1], 1);
else main.votes[messageArray[1]]++;
string[] temp = main.textBox1.Text.Split(' ');
int numVotes = Convert.ToInt32(temp[1]);
numVotes++;
main.textBox1.Text = temp[0] + " " + Convert.ToString(numVotes);
}
if (messageArray[0].CompareTo("start") == 0)
{
main.updateEverything();
}
if(messageArray[0].CompareTo("withdraw") == 0)
{
main.votes[messageArray[1]]--;
string[] temp = main.textBox1.Text.Split(' ');
int numVotes = Convert.ToInt32(temp[1]);
numVotes--;
main.textBox1.Text = temp[0] + " " + Convert.ToString(numVotes);
}
/* clean up */
s.Close();
myList.Stop();
}
}
catch (Exception e)
{
Console.WriteLine("Error..... " + e.StackTrace);
}
You are using a blocking type of connection. The loop you create causes a CPU overhead because of the TcpListener.AcceptConnection(). Your solution is to accept non-blocking socket connections, which is done by receiving data from socket asynchronously.
Here's the msdn link that explains how it works.
http://msdn.microsoft.com/en-us/library/dxkwh6zw.aspx
I see you have string concatenations which basically affects performance; try using a StringBuilder - the message variable should be of type StringBuilder.

WMI query shows a single USB serial COM port?

The code below performs a WMI query to enumerate the working devices on my computer (the OS is windows 7). It retrieves one USB serial port when I have several devices connected to USB plugs. Therefore I have three questions on the topic:
1) Does all USB plugs have a separate com port or is there one com port for all the USB?
2) If I send an array of string to the USB serial port, how will it reach the specific device?
3) Can I extract the USB port from this query to keep it as a string?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Windows.Forms;
namespace MyNamespace
{
class Program
{
static void Main(string[] args)
{
MyClass x = new MyClass();
var com = x.GetCOMs();
foreach (string port in com)
{
Console.WriteLine(port);
}
Console.ReadLine();
}
}
class MyClass
{
public List<string> GetCOMs()
{
List<string> coms = new List<string>();
try
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0");
foreach (ManagementObject obj in searcher.Get())
{
object captionObj = obj["Caption"];
if (captionObj != null)
{
string caption = captionObj.ToString();
if (caption.Contains("(COM"))
{
coms.Add(caption);
}
}
}
m_ParseCOMs(ref coms);
}
catch (ManagementException ex)
{
MessageBox.Show("An error occurred while querying for WMI data: " + ex.Message);
return coms;
}
return coms;
}
private void m_ParseCOMs(ref List<string> comPorts)
{
string[] temp;
List<string> temp2 = new List<string>();
int index = 0;
foreach (string s in comPorts)
{
string temp3 = "";
temp = s.Split(' ');
temp3 += temp[temp.Length - 1] + " - ";
for (int i = 0; i < temp.Length - 1; i++)
{
temp3 += temp[i] + " ";
}
temp2.Insert(index, temp3);
index++;
}
comPorts = temp2;
}
}
}
Many thanks in advance!

How to ping faster when I reach unreachable IP?

I have an app which pings IP or IP range. The problem is that when hosts are closed it takes longer to ping than they are open. When host is closed the time to ping is about 1-2 seconds.
How could I make it faster when hosts are closed?
This is my code:
using System;
using System.Text;
using System.Windows.Forms;
using System.Net.NetworkInformation;
namespace Range_Pinger
{
public partial class PingIPRange : Form
{
uint startIP, endIP, currentIP;
int count = 0;
int open = 0;
int closed = 0;
public PingIPRange()
{
InitializeComponent();
tmrPingInterval.Tick += new EventHandler(tmrPingInterval_Tick);
}
void tmrPingInterval_Tick(object sender, EventArgs e)
{
if (txtTo.Text == string.Empty) Ping(ip2str(startIP));
else
{
if (currentIP >= endIP) tmrPingInterval.Stop();
Ping(ip2str(currentIP));
currentIP++;
}
count++;
tsslPingCount.Text = "Total number of pings: " + count.ToString() +
" Open IPs: " + open.ToString() + " Closed IPs: " + closed.ToString();
}
static uint str2ip(string ip)
{
string[] numbers = ip.Split('.');
uint x1 = (uint)(Convert.ToByte(numbers[0]) << 24);
uint x2 = (uint)(Convert.ToByte(numbers[1]) << 16);
uint x3 = (uint)(Convert.ToByte(numbers[2]) << 8);
uint x4 = (uint)(Convert.ToByte(numbers[3]));
return x1 + x2 + x3 + x4;
}
static string ip2str(uint ip)
{
string s1 = ((ip & 0xff000000) >> 24).ToString() + ".";
string s2 = ((ip & 0x00ff0000) >> 16).ToString() + ".";
string s3 = ((ip & 0x0000ff00) >> 8).ToString() + ".";
string s4 = (ip & 0x000000ff).ToString();
return s1 + s2 + s3 + s4;
}
private void btnPing_Click(object sender, EventArgs e)
{
txtDisplay.Text = string.Empty;
tsslPingCount.Text = string.Empty;
count = 0;
open = 0;
closed = 0;
tmrPingInterval.Interval = int.Parse(nudInterval.Value.ToString());
try
{
startIP = str2ip(txtFrom.Text);
if (txtTo.Text != string.Empty) endIP = str2ip(txtTo.Text);
currentIP = startIP;
tmrPingInterval.Start();
}
catch
{
MessageBox.Show("Invalid input. It must be something like: 255.255.255.255");
}
}
private void btnStop_Click(object sender, EventArgs e)
{
tmrPingInterval.Stop();
}
private void Ping(string address)
{
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
options.DontFragment = true;
string data = "01234567890123456789012345678901";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 120;
try
{
PingReply reply = pingSender.Send(address, timeout, buffer, options) ;
if (reply.Status == IPStatus.Success)
{
open++;
txtDisplay.AppendText("Host " + address + " is open." + Environment.NewLine);
}
else
{
closed++;
txtDisplay.AppendText("Host " + address + " is closed." + Environment.NewLine);
}
}
catch (Exception ex)
{
txtDisplay.SelectedText += Environment.NewLine + ex.Message;
}
}
private void tsmiExit_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
This is what I have now:
[DllImport("iphlpapi.dll", ExactSpelling = true)]
public static extern int SendARP(IPAddress DestIP, int SrcIP, byte[] pMacAddr, ref uint PhyAddrLen);
private void Ping(IPAddress address)
{
byte[] macAddr = new byte[6];
uint macAddrLen = (uint)macAddr.Length;
if (SendARP(address, 0, macAddr, ref macAddrLen) == 0)
{
txtDisplay.AppendText("Host " + address + " is open." + Environment.NewLine);
}
else txtDisplay.AppendText("Host " + address + " is closed." + Environment.NewLine);
}
You shouldn't reduce the timeout. Try to send multiple pings at once async.
var ping = new Ping();
ping.PingCompleted += (sender, eventArgs) =>
{
// eventArgs.Reply.Address
// eventArgs.Reply.Status
};
ping.SendAsync(ip, etc.);
Your address is a string. Thus it will go via DNS first to see if this is possibly a hostname (even if it is an IP address).
I suggest you use the overload taking an IPAddress instead.
I created a live host scanner not too long ago. It uses ARP to check if a computer is online.
An ARP request is much faster than if you'd ping a host.
Here's the code I used to check if a Host is available:
//You'll need this pinvoke signature as it is not part of the .Net framework
[DllImport("iphlpapi.dll", ExactSpelling = true)]
public static extern int SendARP(int DestIP, int SrcIP,
byte[] pMacAddr, ref uint PhyAddrLen);
//These vars are needed, if the the request was a success
//the MAC address of the host is returned in macAddr
private byte[] macAddr = new byte[6];
private uint macAddrLen;
//Here you can put the IP that should be checked
private IPAddress Destination = IPAddress.Parse("127.0.0.1");
//Send Request and check if the host is there
if (SendARP((int)Destination.Address, 0, macAddr, ref macAddrLen) == 0)
{
//SUCCESS! Igor it's alive!
}
If you're interested Nmap also uses this technique to scan for available hosts.
ARP scan puts Nmap and its optimized algorithms in charge of ARP requests. And if it gets a response back, Nmap doesn't even need to worry about the IP-based ping packets since it already knows the host is up. This makes ARP scan much faster and more reliable than IP-based scans. So it is done by default when scanning ethernet hosts that Nmap detects are on a local ethernet network. Even if different ping types (such as -PE or -PS) are specified, Nmap uses ARP instead for any of the targets which are on the same LAN.
EDIT:
This only works within the current subnet! As long as there is no router between the requesting machine and the target it should work fine.
ARP is a non-routable protocol, and can therefore only be used between systems on the same Ethernet network. [...]
arp-scan can be used to discover IP hosts on the local network. It can discover all hosts, including those that block all IP traffic such as firewalls and systems with ingress filters. - Excerpt from NTA-Monitor wiki
For more information on the SendARP function you can check the pinvoke.net documentation.
You need to redesign your application to use multithreading -> tasks. Issue a task for each ping, and when you receive a response from a given host fire an event and update the UI. Changing socket timeout will only help you to reduce the timeout from outrageous to insufferable.
Not sure if this is any help (see final post on the thread), it seems an almost identical problem. What you're butting up against there is the protocol stack's timeout. You can get around it if you use socket to connect as you'll have more control.

Categories

Resources