You may skip this part:
I am creating an application where the client needs to find the server on the same network.
The server:
public static void StartListening(Int32 port)
{
TcpListener server = new TcpListener(IP.GetCurrentIP(), port);
server.Start();
Thread t = new Thread(new ThreadStart(() =>
{
while (true)
{
// wait for connection
TcpClient client = server.AcceptTcpClient();
if (stopListening)
{
break;
}
}
}));
t.IsBackground = true;
t.Start();
}
Let’s say the server is listening on port 12345
then the client:
- get the current ip address of the client let’s say it is 192.168.5.88
-
create a list of all posible ip addresses. The server ip address will probably be related to the client’s ip if they are on the same local network therefore I construct the list as:
192.168.5.0 192.168.5.1 192.168.5.2 192.168.5.3 .....etc ..... 192.168.0.88 192.168.1.88 192.168.2.88 192.168.3.88 ...etc 192.0.5.88 192.1.5.88 192.2.5.88 192.3.5.88 192.4.5.88 ..... etc 0.168.5.88 1.168.5.88 2.168.5.88 3.168.5.88 4.168.5.88 .... etc
Then I try to connect with every possible ip and port 12345. If one connection is successful then that means that I found the address of the server.
Now my question is:
Now I have done this in two ways. I know just the basics about threads and I don’t know if this is dangerous but it works really fast.
// first way
foreach (var ip in ListOfIps)
{
new Thread(new ThreadStart(() =>
{
TryConnect(ip);
})).Start();
}
the second way I belive it is more safe but it takes much more time:
// second way
foreach (var ip in ListOfIps)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(TryConnect), ip);
}
I have to call the TryConnect method about 1000 times and each time it takes about 2 seconds (I set the connection timeout to 2 seconds). What will be the most efficient and secure way of calling it 1000 times?
EDIT 2
Here are the results using different techniques:
1) Using threadpool
..
..
var now = DateTime.Now;
foreach (var item in allIps)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), item);
}
ThreadPool.QueueUserWorkItem(new WaitCallback(PrintTimeDifference), now);
}
static void PrintTimeDifference(object startTime)
{
Console.WriteLine("------------------Done!----------------------");
var s = (DateTime)startTime;
Console.WriteLine((DateTime.Now-s).Seconds);
}

It took 37 seconds to complete
2) Using threads:
..
..
var now = DateTime.Now;
foreach (var item in allIps)
{
new Thread(new ThreadStart(() =>
{
DoWork(item);
})).Start();
}
ThreadPool.QueueUserWorkItem(new WaitCallback(PrintTimeDifference), now);

It took 12 seconds to complete
3) Using tasks:
..
..
var now = DateTime.Now;
foreach (var item in allIps)
{
var t = Task.Factory.StartNew(() =>
DoWork(item)
);
}
ThreadPool.QueueUserWorkItem(new WaitCallback(PrintTimeDifference), now);
}
static void PrintTimeDifference(object startTime)
{
Console.WriteLine("------------------Done!----------------------");
var s = (DateTime)startTime;
Console.WriteLine((DateTime.Now-s).Seconds);
}

It took 8 seconds!!
In this case I would prefer the solution with the ThreadPool-Threads, because creating 1000 Threads is a heavy operation (when you think of the memory each thread gets).
But since .NET 4 there is another solution with the class
Task.Tasks are workloads which can be executed in parallel. You can define and run them like this:
You don’t have to care about the number of threads used because the runtime environment handles that. So if you have the possibility to split your workload into smaller packages which can be executed in parallel I would use Tasks to do the work.