How to scan local LAN network? - c#

I have created a program in C# which scan all PCs in LAN network, and then print out list of IP and computer name of it. This code here I covered in YouTube of someone. But when I try to scan, it always return an error:
Additional information: An exception occurred during a Ping request.
I try to turn off firewall in all PCs in LAN network, but still have this problem. I spend times to figure out, but still don't know what to do next.
Thread myThread = null;
public void scan(string subnet)
{
Ping myPing;
PingReply reply;
IPAddress addr;
IPHostEntry host;
for (int i = 1; i < 255; i++)
{
string subnetn = "." + i.ToString();
myPing = new Ping();
reply = myPing.Send(subnet + subnetn);
if (reply.Status == IPStatus.Success)
{
try
{
addr = IPAddress.Parse(subnet + subnetn);
host = Dns.GetHostEntry(addr);
txtHosts.AppendText(subnet + subnetn + host.HostName.ToString() + "Up");
}
catch
{
}
}
}
}
private void cmdScan_Click(object sender, EventArgs e)
{
myThread = new Thread(() => scan(txtIP.Text));
myThread.Start();
if (myThread.IsAlive)
{
cmdStop.Enabled = true;
cmdScan.Enabled = false;
txtIP.Enabled = false;
}
}
private void cmdStop_Click(object sender, EventArgs e)
{
myThread.Suspend();
cmdScan.Enabled = true;
cmdStop.Enabled = false;
txtIP.Enabled = true;
}
}

Related

C# check multiple client connections

I am currently developing a one-to-many relationship between one server and many clients.
Everytime a client connects I append to the client list: clientList.Add(client);
I wrote the following code to check the "pulse" of the client connection as to see if the client is still connected and currently updating the toolStripStatusLabel1
This seems to work well when checking one connection and in addition, I added the exception cleanup() when trying to send data so that it should check at all scenarios(Feel free to give your opinion).
My question now is, how do I check the connection from multiple clients?
Please find below the reference code:
private void StartListen()
{
//Creating a TCP Connection and listening to the port
tcpListener = new TcpListener(System.Net.IPAddress.Any, 6666);
tcpListener.Start();
toolStripStatusLabel1.Text = "Listening on port 6666 ...";
int counter = 0;
appStatus = 0;
while (true)
{
try
{
client = tcpListener.AcceptTcpClient();
counter++;
clientList.Add(client);
IPEndPoint ipend = (IPEndPoint)client.Client.RemoteEndPoint;
//Updating status of connection
toolStripStatusLabel1.Text = "Connected from " + IPAddress.Parse(ipend.Address.ToString());
appStatus = 1;
th_outPutStream = new Thread(delegate () { outPutStream(client); });
th_outPutStream.Start();
th_inPutStream = new Thread(delegate () { inPutStream(client); });
th_inPutStream.Start();
th_checkConnection = new Thread(checkConnection);
th_checkConnection.Start();
}
catch (Exception err)
{
Cleanup();
}
}
}
private void checkConnection()
{
bool status = true;
while (status == true)
{
status = IsConnected();
if (status == true)
{
System.Threading.Thread.Sleep(3000); //Wait 3 seconds then try again
}
else
{
Cleanup();
}
}
}
private bool IsConnected()
{
try
{
return !(client.Client.Poll(1, SelectMode.SelectRead) && client.Client.Available == 0);
}
catch (SocketException) { Cleanup(); return false; }
}
I did this by simply creating a forloop for each client in my client list:
private void checkConnection()
{
bool status = true;
while (true)
{
for (int i = 0; i < clientList.Count; i++)
{
Debug.WriteLine(clientList.Count);
status = IsConnected(i);
if (status == true)
{
}
else
{
Cleanup(i);
}
}
System.Threading.Thread.Sleep(3000); //Wait 3 seconds then try again
}
}
private bool IsConnected(int i)
{
try
{
return !(clientList[i].Client.Poll(1, SelectMode.SelectRead) && clientList[i].Client.Available == 0);
}
catch (SocketException) { Cleanup_dep(); return false; }
}

How to dynamically change ip address of client in c#?

In my client-server winform app,want to change ip address of client each time i run it.
A text box should take ip address of my client and then connect to server using local ip which is on same computer.
Client code:
public partial class Form1 : Form
{
System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();
NetworkStream serverStream;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void ConnectToServer()
{
string server_localip = GetLocalIP();
clientSocket.Connect(server_localip, 8888);
}
public void SendData(string dataTosend)
{
if (string.IsNullOrEmpty(dataTosend))
return;
NetworkStream serverStream = clientSocket.GetStream();
byte[] outStream = new byte[33];
outStream = System.Text.Encoding.ASCII.GetBytes(dataTosend);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
}
public void CloseConnection()
{
clientSocket.Close();
}
public string ReceiveData()
{
StringBuilder message = new StringBuilder();
serverStream = clientSocket.GetStream();
serverStream.ReadTimeout = 100;
//the loop should continue until no dataavailable to read and message string is filled.
//if data is not available and message is empty then the loop should continue, until
//data is available and message is filled.
while (true)
{
if (serverStream.DataAvailable)
{
int read = serverStream.ReadByte();
if (read > 0)
message.Append((char)read);
else
break;
}
else if (message.ToString().Length > 0)
break;
}
return message.ToString();
}
public string GetLocalIP()
{
IPHostEntry host;
host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
return "127.0.0.1";
}
private void btnConnect_Click(object sender, EventArgs e)
{
ConnectToServer();
btnConnect.Text = "Connected";
}
private void btnRegister_Click(object sender, EventArgs e)
{
//if (!Regex.IsMatch(txtPrivateId.Text, #"\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*"))
//{
// lblError.Text ="Please type a valid IMPI.";
//}
//if (!Regex.IsMatch(txtPublicId.Text, "[^0-9]"))
//{
// lblError.Text = lblError.Text + "\nPlease type a valid IMPU.";
//}
//else
//{
lblError.Text = "";
string data = txtPrivateId.Text + ";" + txtPublicId.Text;
for (int i = 0; i < 1; i++)
{
SendData(data);
}
string rec = null;
rec = ReceiveData();
txtReceive.Text = rec;
}
}
Any guidance would be appreciated..
you can use netsh to change your ip address:
netsh interface ip set address [adapter name] static [ip address] [subnet mask] [gateway] [interface metric]
try the code below:
Process p = new Process();
ProcessStartInfo psi = new ProcessStartInfo("netsh", "interface ip set address \"Local Area Connection\" static 192.168.0.10 255.255.255.0 192.168.0.1 1");
p.StartInfo = psi;
p.Start();
and remember that your application should be running in elevated permissions.
"Local Area Connection" should match your adapter name
for more information about the netsh command line switches visit the Microsoft knowledge base article below:
http://support.microsoft.com/kb/242468

detect Internet Connection/Disconnection in Console App C#

I wrote a small console app which connects with a remote site, downloads some data and process it. As it is network operation so I want my application to be intelligent enough to go to pause state when there is no internet connection. If internet connection gets available it should resume its working.
What I done so far is if I run application it starts downloading data from remote site. If I disconnects internet connection it behaves correctly by displaying appropriate info. But as soon as network connection is up it resumes and only download data for one iteration of while loop.
Here is the code:
class Program
{
static bool networkIsAvailable = false;
static StreamWriter writer = null;
static int i = 1;
static string URI = "http://xxxxxxxxxxxxxxxxxxxxxxxxxxx/" + i + "/";
static void Main(string[] args)
{
writer = new StreamWriter("c:\\StudentsList.txt", true);
NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface nic in nics)
{
if (
(nic.NetworkInterfaceType != NetworkInterfaceType.Loopback && nic.NetworkInterfaceType != NetworkInterfaceType.Tunnel) &&
nic.OperationalStatus == OperationalStatus.Up)
{
networkIsAvailable = true;
}
}
if (!networkIsAvailable)
Console.WriteLine("Internet connection not available! We resume as soon as network is available...");
else
ConnectToPUServer();
}
public static void ConnectToPUServer()
{
var client = new WebClient();
while (i < 500 && networkIsAvailable)
{
string html = client.DownloadString(URI);
//some data processing
Console.WriteLine(i);
i++;
URI = "http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/" + i + "/";
}
}
static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
networkIsAvailable = e.IsAvailable;
if (!networkIsAvailable)
Console.WriteLine("Internet connection not available! We resume as soon as network is available...");
while (!networkIsAvailable)
{
//waiting for internet connection
}
ConnectToPUServer();
Console.WriteLine("Complete.");
writer.Close();
}
}
After resuming, why while loop of ConnectToPUServer is executing only once??
Thanks.
If NetworkChange_NetworkAvailabilityChanged is being fired every time a NIC changes it status there is no need for the while loop to wait for a connection
I also move the writer.close and the end of the method ConnectToPUServer
public static void ConnectToPUServer()
{
var client = new WebClient();
while (i < 500 && networkIsAvailable)
{
string html = client.DownloadString(URI);
//some data processing
Console.WriteLine(i);
i++;
URI = "http://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/" + i + "/";
}
Console.WriteLine("Complete.");
writer.Close();
}
static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
networkIsAvailable = e.IsAvailable;
if (!networkIsAvailable)
{
Console.WriteLine("Internet connection not available! We resume as soon as network is available...");
}
else
{
ConnectToPUServer();
}
}

disconnect/close a client [duplicate]

This question already has an answer here:
C# -- TcpListener.Start() causing SocketException with message "Only one usage of each socket address"
(1 answer)
Closed 2 years ago.
I have a simple client-server application which works like this: the server is always listening (in a separate thread) for a client connection (which sends the name of process that it wants the server to kill).
Here is the server:
private void btnStart_Click(object sender, EventArgs e)
{
_port = int.Parse(comboBoxPorts.SelectedItem.ToString());
_tcpListener = new TcpListener(_ipAddress, _port);
_keepRunning = true;
_listenerThread = new Thread(Listen);
HandleListenerThreadStartListenEvent += HandleListenerThreadStartedEventMethod;
ListenerThreadStartedEvent += HandleListenerThreadStartListenEvent;
_listenerThread.Start();
}
private void btnStop_Click(object sender, EventArgs e)
{
if (_tcpListener != null)
{
_keepRunning = false;
if (_tcpListener.Server.Connected)
{
_tcpListener.Server.Disconnect(true);
}
_tcpListener.Stop();
}
labelServerStatus.Text = "Server is stopped";
comboBoxPorts.Enabled = true;
btnStart.Enabled = true;
btnStop.Enabled = false;
}
private void Listen()
{
try
{
_tcpListener.Start();
OnListenerThreadStartListenEvent(); // just update the GUI
}
catch(Exception e)
{
MessageBox.Show("Port " + _port + " is NOT available." + Environment.NewLine +
"Please choose another one: " + e.Message);
return;
}
_keepRunning = true;
string ballonMessage = "Socket Server Running at " + _ipAddress + ", port: " + _port;
notifyIcon1.ShowBalloonTip(2000, "Simplex Listener", ballonMessage, ToolTipIcon.Info);
while (_keepRunning)
{
try
{
#region using AcceptSocket()
_clientSocket = _tcpListener.AcceptSocket();
string checkString = string.Empty;
IPAddress ipOfClient = ((IPEndPoint) _clientSocket.LocalEndPoint).Address;
notifyIcon1.ShowBalloonTip(2000, "Simplex Listener", "New client has connected from ip " + ipOfClient, ToolTipIcon.Info);
byte[] buffer = new byte[SIZE_OF_BUFFER];
int bytesReceived = _clientSocket.Receive(buffer);
// Concatenate chars as bytes to a received string.
for (int i = 0; i < bytesReceived; i++)
checkString += Convert.ToChar(buffer[i]);
//..... getting the name of process and kill it (and than open it...
RestartProcess(nameOfProcess, windowName, pathToExeFile);
// Client is waiting to know operation is complete- so send him some char...
ASCIIEncoding encoder = new ASCIIEncoding();
_clientSocket.Send(encoder.GetBytes("v"));
_clientSocket.Disconnect(true);
_clientSocket.Close();
#endregion
}
catch (Exception )
{
}
}
}
The client side:
public void RestartTheSoftwareInServerComputer(string ipOfServer, int portNumber)
{
TcpClient client = new TcpClient();
if (_serverEndPoint == null)
{
_serverEndPoint = new IPEndPoint(IPAddress.Parse(ipOfServer), portNumber);
}
client.Connect(_serverEndPoint);
// Send the command to the server:
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("....detailsOfProcess....");
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
// Now, wait for the server's response [which means the process had been restart].
NetworkStream stream = client.GetStream();
byte[] bytes = new byte[5];
stream.Read(bytes, 0, 5);
string response = Encoding.UTF8.GetString(bytes, 0, 1);
if (response.Equals("x"))
{
throw new Exception("Failed to restart X software.");
}
stream.Close();
client.Close();
}
When I stop and restart the server (when no client had connected), then everything is OK.
The problem is when the server got some client connected, and is restarted, then the client has disconnected and the server needs to be restarted. When we hit the "START SERVER" again it will get the exception:
Only one usage of each socket address (protocol/network address/port)
is normally permitted.
How should I close the port?
When you exit your server, you should call _tcpListener.Stop() to close the main socket that the server is listening on.
Edit: You could also try to call _listenerThread.Join() in your stop button click, to wait for the listener thread to finish, before starting the next one.
private void btnStop_Click(object sender, EventArgs e)
{
if (_tcpListener != null)
{
_keepRunning = false;
if (_tcpListener.Server.Connected)
{
_tcpListener.Server.Disconnect(true);
_tcpListener.Stop();
if (_clientSocket != null)
{
_clientSocket.Close();
_clientSocket = null;
}
_listenerThread.Join();
}
}
labelServerStatus.Text = "Server is stopped";
comboBoxPorts.Enabled = true;
btnStart.Enabled = true;
btnStop.Enabled = false;
}
EDIT 2:
here is a windows form that does similar to your server. I didn't need a client, just use "telnet localhost 49152" from a command prompt to 'pretend' to be the client connecting.
public partial class Form1 : Form
{
private TcpListener _tcpListener;
private bool _keepRunning;
private Thread _listenerThread;
private Socket _clientSocket;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var address = IPAddress.Parse("127.0.0.1");
_tcpListener = new TcpListener(address, 49152);
_keepRunning = true;
_listenerThread = new Thread(Listen);
_listenerThread.Start();
button1.Enabled = false;
button2.Enabled = true;
}
private void Listen()
{
try
{
_tcpListener.Start();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
return;
}
_keepRunning = true;
while (_keepRunning)
{
try
{
_clientSocket = _tcpListener.AcceptSocket();
var buffer = new byte[8192];
var bytesReceived = _clientSocket.Receive(buffer);
var checkString = String.Empty;
if (_keepRunning)
{
// bytesReceived can be 0 if the remote socket disconnected
if (bytesReceived > 0)
{
checkString = Encoding.ASCII.GetString(buffer, 0, bytesReceived);
// Client is waiting to know operation is complete- so send him some char...
var encoder = new ASCIIEncoding();
_clientSocket.Send(encoder.GetBytes("v"));
}
if (_clientSocket.Connected) _clientSocket.Disconnect(true);
}
_clientSocket.Close();
}
catch (Exception ex)
{
// really should do something with these exceptions
}
}
}
private void button2_Click(object sender, EventArgs e)
{
if (_tcpListener != null)
{
_keepRunning = false;
if (_tcpListener.Server.Connected)
{
_tcpListener.Server.Disconnect(true);
}
_tcpListener.Stop();
if (_clientSocket != null)
{
_clientSocket.Close();
_clientSocket = null;
}
_listenerThread.Join();
}
button1.Enabled = true;
button2.Enabled = false;
}
}
There are a lot of problems with this code, e.g. sharing variables across threads etc. but on my machine the Join doesn't seem to block for any length of time. The problem with _keepRunning is that on certain systems it's possible for one thread to not see the change from true to false, because it gets optimised or cached. You should really use some form of thread synchronisation, make it volatile, or wrap it in a lock etc. I'd suggest you have a read here about this. I'd also suggest you have a read up on Sockets too, or if as other commenters have mentioned, if you aren't interested in learning about all the idiosyncrasies of sockets and threading, perhaps you should look for a higher level library that hides it all?

How do I get all servers' IP which are listening on specific port LAN?

How do I get all servers IP which are listening on specific port (Ex:9090) in LAN
I have already read some basics information about multicast,anycast ,unicast and broadcast and it seems like broadcast is the one meant for my application.
I am thinking of two ideas .. Use TCP protocol to Connect to all IP Addresses (192.168.1.1-254) in parallel on port 9090 and set a little time period to the connection timeout. just to check if there's any responce. (but it doesn't seem like a good idea)Use UDP protocol and broadcast a message like "hello" and check for response then get all IP Addresses which respond.
So which idea should I pick, are there better ideas to do it?
I would also like to know if my broadcast-ed message is received to the server and how to get the IP address of it.
I've done it with TCP to search all server that is listening on a specific port.
Its not an idle solution, but it worked for me.
I've created a userControl with a public function Initialize to pass the port that i want to scan for servers.
public ServerDiscovery()
{
InitializeComponent();
// statusLabel.Image = imageState.Images[2];
timer.Elapsed += timer_tick;
}
int port = 0;
bool busy = false; // to tell that the function is busy with scanning.
public void Initialize(int port)
{
this.port = port;
}
System.Timers.Timer timer = new System.Timers.Timer(5000);
List<SocketAsyncEventArgs> list = new List<SocketAsyncEventArgs>();
// this list to hold all sockets that created to connect to IP .. to DISPOSE it later
HashSet<string> usedIP = new HashSet<string>();
//usedIP will be explained later.
public IPEndPoint getAddress()
{ //this function to get the IPEndPoint of the selected server from listview.
if (listServer.SelectedItems.Count > 0)
{
if (listServer.SelectedItems[0].ImageIndex == 0)
{
ListViewItem item = listServer.SelectedItems[0];
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(item.SubItems[1].Text), port);
return ep;
}
}
return null;
}
public void Refresh() //to scan for servers
{
if (!busy)
{
usedIP.Clear();
listServer.Items.Clear();
// statusLabel.Text = "Scanning for servers.";
// statusLabel.Image = Image.FromFile("loading.gif");
// btnRefresh.Enabled = false;
busy = true;
timer.Start();
IPAddress[] IpA = Dns.GetHostByName(Dns.GetHostName()).AddressList;
for (int j = 0; j < IpA.Length ; j++)
{
if (IpA[j].AddressFamily == AddressFamily.InterNetwork) // to make sure it's an IPV4
{
string scanIP = IpA[j].ToString().Substring(0, IpA[j].ToString().LastIndexOf(".")) + ".";
if (!usedIP.Contains(scanIP))
//usedIP is a hashset that holds the first 3 parts on an ip (ex:"192.168.1." from "192.168.1.30") i used this to avoid scanning the same ip addresses more than once .. like if i had a wireless network ip ("192.168.1.5") and an Ethernet Network ip ("192.168.1.5"). so with that hashset it will scan once.
{
usedIP.Add(scanIP);
Parallel.For(1, 255, i =>
{
Scan(scanIP + i);
});
}
}
}
}
}
private void Scan(string ipAdd)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ipAdd), port);
e.UserToken = s;
e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed);
list.Add(e); // add the created socket to a list to dispose when time is up.
s.ConnectAsync(e);
}
private void e_Completed(object sender, SocketAsyncEventArgs e)
{
if (e.ConnectSocket != null) //if there's a responce from the server [e.ConnectSocket] will not be equal null.
{
StreamReader sr = new StreamReader(new NetworkStream(e.ConnectSocket));
ListViewItem item = new ListViewItem();
string[] cmd = sr.ReadLine().Split('<'); in my server constructor this line will receive a string like "PC_NAME<Available" ..
item.Text = cmd[0];
item.SubItems.Add(((IPEndPoint)e.RemoteEndPoint).Address.ToString());
item.SubItems.Add(cmd[1]);
if (cmd[1] == "Busy")
item.ImageIndex = 1;
else
item.ImageIndex = 0;
AddServer(item);
list.Remove(e); //active server should be remove from the list that holds the sockets and disposed.. because there's no need to keep connection after showing that this server is active.
((Socket)e.UserToken).Dispose();
}
}
delegate void AddItem(ListViewItem item);
private void AddServer(ListViewItem item)
{
if (InvokeRequired)
{
Invoke(new AddItem(AddServer), item); //just to add an item from a background thread.
return;
}
listServer.Items.Add(item);
}
private void timer_tick(object sender, EventArgs e)
{
busy = false; //when time's up .. set busy to false so we can scan again
timer.Stop();
foreach (var s in list) //dispose all sockets that's trying to connect and waiting for a response
{
try
{
((Socket)s.UserToken).Dispose();
}
catch { }
}
//this.Invoke((MethodInvoker)delegate // for design
// {
// btnRefresh.Enabled = true;
// btnRefresh.BorderStyle = Border3DStyle.Raised;
// statusLabel.Text = "Ready.";
// statusLabel.Image = imageState.Images[2];
// });
}
private void btnRefresh_Click(object sender, EventArgs e)
{
// btnRefresh.BorderStyle = Border3DStyle.Sunken;
Refresh();
}
// private void listServer_KeyUp(object sender, KeyEventArgs e)
// {
// if (e.KeyCode == Keys.F5)
// {
// btnRefresh_Click(sender, (EventArgs)e);
// }
// }
}
Again this's not an ideal solution that works on any case but it worked fine with me.

Categories