This question already has answers here:
find all ip address in a network
(5 answers)
Closed 8 years ago.
So I am making a network scanner in c# to show all connected devices to the same network as you. The way I am doing this is by doing a ping command on all IP's from 192.168.0.1 to 192.168.0.255.
private void IPlook_Tick(object sender, EventArgs e)
{
Properties.Settings.Default.nextIP += 1;
if (Properties.Settings.Default.nextIP >= 255)
{
IPlook.Stop();
}
string IP = "192.168.0." + Properties.Settings.Default.nextIP.ToString();
CurIP.Text = IP;
//See if online
try
{
Ping ping = new Ping();
PingReply pingreply = ping.Send(IP);
if (pingreply.Status == IPStatus.Success)
{
string Hostname = Dns.GetHostByAddress(IP).HostName;
dataGridView1.Rows.Add(Hostname, IP, "");
}
else
{
}
}
catch (Exception er)
{
MessageBox.Show("Something Went Wrong", "Error Alert", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
This is working fine but the problem is it is taking a very long time and making the program laggy. I have set the interval on the timer to 50.
Any help is appreciated.
Legitimate
How about firing them all off at once (from an async method):
IPAddress start = IPAddress.Parse("192.168.1.1");
var bytes = start.GetAddressBytes();
var leastSigByte= start.GetAddressBytes().Last();
var range= 255 - leastSigByte;
var pingReplyTasks = Enumerable.Range(leastSigByte,range)
.Select(x=>{
var p = new Ping();
var bb = start.GetAddressBytes();
bb[3] = (byte)x;
var destIp = new IPAddress(bb);
var pingResultTask = p.SendPingAsync(destIp);
return new{pingResultTask, addr = destIp};
})
.ToList();
await Task.WhenAll(pingReplyTasks.Select(x=>x.pingResultTask));
foreach(var pr in pingReplyTasks)
{
var tsk = pr.pingResultTask;
var pingResult = tsk.Result; //we know these are completed tasks
var ip = pr.addr;
Console.WriteLine("{0} : {1}",ip,pingResult.Status);
}
You probably don't want to ping addresses ending in 0 or 255.
You are running the pings one after the other. This means that you must wait for the timeout to expire 255 times. Start multiple pings at the same time. Using await would make a lot of sense here.
Also, unblock the UI thread so that the UI is not frozen while this is in progress. Many techniques are available for doing that. await happens to solve this problem as well.
I don't see why you are using a timer. If there is no reason for that simply delete all timer stuff. Use a loop.
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
// Can build your list of IPs using a for loop
List<IPAddress> ips = new List<IPAddress>
{
new IPAddress(new byte[] {192, 168, 0, 1}),
new IPAddress(new byte[] {192, 168, 0, 2}),
// More ips in this list.
};
// Exactly what do you do with initiated tasks will depend on your specific scenario.
List<Task> tps = new List<Task>();
foreach(var ip in ips)
{
tps.Add(InitiatePing(ip));
}
// Needed so that console app doesn't exit..
Console.ReadLine();
}
private static async Task InitiatePing(IPAddress ip)
{
// Note, this API is different from SendAsync API you are using
// You may also want to reuse Ping instance instead of creating new one each time.
var result = await new Ping().SendPingAsync(ip);
// Process your result here, however you want.
Console.WriteLine(result.Address + "-" + result.Status + "-" + result.RoundtripTime);
}
}
}
Well if I'm reading your code correctly you're allowing the timer to fire 255 times and are pinging exactly one computer in each execution. I'm not sure why you're using a Settings class to store the current iteration number.
You could loop over 1 to 255 and launch each Ping request asynchronously using the Ping.SendAsync method. There is no need for a timer.
See also this question and answers/comments about broadcast pinging.
Related
I'm having a very peculiar issue with the serial port class in C# (using .NET 4.5 as a target). Our application needs the ability to switch between (close then open another) serial COM ports which are all USB 1.1 virtual COM port devices. The problem I'm having has two symptoms that may be related. First, we can only connect to our device after having already read from it using another terminal emulator or similar application and even then only once. After one successful connection all other attempts after closing and re-opening the port will never receive data (DataReceivedEvent never fires). The only workaround I have found to this is to manually drive the RTS signal as shown below (even though every other serial library or emulation program requires no handshaking to talk to this device, including TerraTerm, Java, and PySerial).
Second, even then, while the port may be freely opened and closed successful, occasionally (1/30 ish) the Open() or Close() functions take precisely 30 seconds to finish (30008 ms measured via a diagnostic Stopwatch) where it would normally take a mere 5-8 ms. There seems to be no explanation for this. Any thoughts?
Measures already used to try eliminating or mitigating the problem:
Attempts to Open or Close the port are executed as separate tasks in the thread pool so that they can be terminated or aborted cleanly after a specified period of time if unsuccessful (I use 60 seconds for this value in testing)
I've added various time delays both short (100 ms) and extreme (5000 ms) in every conceivable place with no effect (between port close and reopen, between open and close, and between open/close and RTS true/false
Double triple and quadruple checked the designed port parameters for our USB serial device
I've looked at this article by bvoigt and this article by Zach Saw which both seem to suggest that there are deeply rooted issues with .NET SerialPort class. This has left me with the impression that a third party library might be the best option (there are some good candidates on NuGet). Ultimately this will be used as the serial port within a WPF application.
Before anyone asks, no, simply opening the port and leaving it open is not an option in our application and, frankly, this is something that works seamlessly 100% of the time with the same device from the same hosts with the same driver in other languages' standard serial implementations (see above).
Please see the simple exemplary application below which I have been using to successfully reproduce this problem. Any pointers in the right direction are greatly appreciated!!!
SerialTestApplication.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Diagnostics;
using System.Threading;
namespace SerialTestApplication
{
class Program
{
private SerialPort S = new SerialPort();
private bool S_active = false;
private int succeed = 0;
private int fail = 0;
static void Main(string[] args)
{
Program P = new Program();
System.Threading.Thread.Sleep(1000);
var test_timer = new Stopwatch();
test_timer.Start();
for (int a = 0; a < 100; a++)
{
P.ConnectSerial(P);
P.CloseSerial(P);
}
Console.WriteLine("EXIT");
System.Threading.Thread.Sleep(1000);
Console.ReadLine();
}
private bool ConnectSerial(Program P)
{
if (S.IsOpen)
{
fail++;
Console.WriteLine("PORT NOT CLOSED YET");
return false;
}
// Setup The Serial COMM Port
S.PortName = "COM1";
S.BaudRate = 115200;
S.Handshake = System.IO.Ports.Handshake.None;
S.Parity = Parity.None;
S.DataBits = 8;
S.StopBits = StopBits.One;
// Write Properties
S.WriteBufferSize = 2048;
S.WriteTimeout = 500;
// Read Properties
S.ReceivedBytesThreshold = 1;
S.ReadBufferSize = 2048;
S.ReadTimeout = 500;
try
{
S_active = false;
if (!P.OpenSerial(P))
{
fail++;
return false;
}
var connection_timer = new Stopwatch();
connection_timer.Start();
while (S.IsOpen && !S_active)
{
if (connection_timer.ElapsedMilliseconds > 1000)
{
fail++;
CloseSerial(this);
Console.WriteLine("Succeed/Fail: " + succeed + " " + fail);
return false;
}
}
succeed++;
Console.WriteLine("Succeed/Fail: " + succeed + " " + fail);
Console.WriteLine(S.BytesToWrite + " " + S.BytesToRead);
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
private void Receive(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (S.IsOpen)
{
S_active = true;
S.ReadExisting();
}
}
private bool OpenSerial(Program P)
{
Task OpenAttempt = Task.Factory.StartNew(() =>
{
try
{
if (S.IsOpen)
{
Console.WriteLine("PORT STILL OPEN!");
return;
}
S.Open();
S.DiscardInBuffer();
S.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Receive);
S.RtsEnable = true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
});
var open_timer = new Stopwatch();
open_timer.Start();
OpenAttempt.Wait(60000);
Console.WriteLine("Opened In: " + open_timer.ElapsedMilliseconds);
return S.IsOpen;
}
private void CloseSerial(Program P)
{
Task CloseAttempt = Task.Factory.StartNew(() =>
{
try
{
S.RtsEnable = false;
S.Close();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
});
var close_timer = new Stopwatch();
close_timer.Start();
CloseAttempt.Wait(60000);
Console.WriteLine("Closed In: " + close_timer.ElapsedMilliseconds);
}
}
}
EDIT 1
I've found one issue with this but unfortunately it doesn't solve the core "takes 30 seconds to finish the Open() or Close() method" problem. The way I am recycling (closing and reopening) the SerialPort object in this test application adds a new DataReceived event handler every time the port is reopened. Basically after closing/opening the port 10 times there will be ten DataReceived handlers associated with the object. To correct that I'm now letting Close() Dispose() the SerialPort object then setting the reference to null and creating a completely new instance of SerialPort on the next open. That seems to ensure that the serial port is properly released so long as the USB cable is not physically pulled out of the computer.
This question already has answers here:
Handling multiple requests with C# HttpListener
(3 answers)
Closed 8 years ago.
I have this HttpListener, which works perfect for a single requesst, but then it shuts down after finishing up the request. What I'm interested in, is a listener that keeps up the connection with the client until there's no more files in the specified URL. I've tried fiddling around with threads and asynchronous calls, but I haven't been able to make anything of it working thus far. I just have a hard time imagining there isn't some relatively easy way to get a HttpListener to keep up the connection instead of shutting down after completing each request.
public static void Listener(string[] prefixes)
{
if (!HttpListener.IsSupported)
{
Console.WriteLine("Windows XP SP2 or Server 2003 is required to use the HttpListener class.");
return;
}
// URI prefixes are required,
// for example "http://contoso.com:8080/index/".
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
// Create a listener.
HttpListener listener = new HttpListener();
// Add the prefixes.
foreach (string s in prefixes)
{
listener.Prefixes.Add("http://" + s + "/");
}
listener.Start();
Console.WriteLine("\nListening...");
HttpListenerContext context = listener.GetContext();
Console.WriteLine("Request received...\n");
HttpListenerRequest request = context.Request;
// Obtain a response object.
string url = context.Request.RawUrl;
string[] split = url.Split('/');
int lastIndex = split.Length - 1;
int x, y, z;
x = Convert.ToInt32(split[lastIndex]);
y = Convert.ToInt32(split[lastIndex - 1]);
z = Convert.ToInt32(split[lastIndex - 2]);
HttpListenerResponse response = context.Response;
#region Load image and respond
// Load the image
Bitmap bm = new Bitmap("C:\\MyFolder\\image_1\\");
MemoryStream bmStream = new MemoryStream();
bm.Save(bmStream, ImageFormat.Png);
byte[] buffer = bmStream.ToArray();
// Get a response stream and write the response to it.
response.ContentLength64 = bmStream.Length;
response.ContentType = "image/png";
response.KeepAlive = true;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
// You must close the output stream.
output.Close();
listener.Stop();
#endregion
And here's the Program:
class Program
{
static void Main(string[] args)
{
string name = (args.Length < 1) ? Dns.GetHostName() : args[0];
try
{ //Find the IPv4 address
IPAddress[] addrs = Array.FindAll(Dns.GetHostEntry(string.Empty).AddressList,
a => a.AddressFamily == AddressFamily.InterNetwork);
Console.WriteLine("Your IP address is: ");
foreach (IPAddress addr in addrs)
Console.WriteLine("{0} {1}", name, addr);
//Automatically set the IP address
string[] ips = addrs.Select(ip => ip.ToString()).ToArray();
Response.Listener(ips);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
//Manually setting the IP - not optimal!
//string[] ipstring = new string[1] { "10.10.180.11:8080" };
//Response.Listener(ipstring);
}
}
Yes - you're calling GetContext once, serving that request, then stopping.
Instead, you should be calling GetContext in a loop. Depending on whether you want to be able to handle multiple requests concurrently or not, you might have GetContext in one thread, and then hand off each request to a separate (probably thread-pool) thread to respond to it.
The slightly tricky bit is shutting down - if you want a clean shutdown, you'll need to work out when to stop the loop (and what to do if you're in the middle of a GetContext call), and wait for outstanding requests to complete.
It stops listening after processing one request because you just stop listening. You need to implement something like a waiting loop.
Example which should help you can be found on codeproject - example.
Pay attention to this part of the code and how it is used in the example:
private void startlistener(object s)
{
while (true)
{
////blocks until a client has connected to the server
ProcessRequest();
}
}
I'm developing an application that manages devices in the network, at a certain point in the applicaiton, I must ping (actually it's not a ping, it's a SNMP get) all computers in the network to check if it's type is of my managed device.
My problem is that pinging all computers in the network is very slow (specially because most of them won't respond to my message and will simply timeout) and has to be done asynchronously.
I tried to use TLP to do this with the following code:
public static void FindDevices(Action<IPAddress> callback)
{
//Returns a list of all host names with a net view command
List<string> hosts = FindHosts();
foreach (string host in hosts)
{
Task.Run(() =>
{
CheckDevice(host, callback);
});
}
}
But it runs VERY slow, and when I paused execution I checked threads window and saw that it only had one thread pinging the network and was thus, running tasks synchronously.
When I use normal threads it runs a lot faster, but Tasks were supposed to be better, I'd like to know why aren't my Tasks optimizing parallelism.
**EDIT**
Comments asked for code on CheckDevice, so here it goes:
private static void CheckDevice(string host, Action<IPAddress> callback)
{
int commlength, miblength, datatype, datalength, datastart;
string output;
SNMP conn = new SNMP();
IPHostEntry ihe;
try
{
ihe = Dns.Resolve(host);
}
catch (Exception)
{
return;
}
// Send sysLocation SNMP request
byte[] response = conn.get("get", ihe.AddressList[0], "MyDevice", "1.3.6.1.2.1.1.6.0");
if (response[0] != 0xff)
{
// If response, get the community name and MIB lengths
commlength = Convert.ToInt16(response[6]);
miblength = Convert.ToInt16(response[23 + commlength]);
// Extract the MIB data from the SNMP response
datatype = Convert.ToInt16(response[24 + commlength + miblength]);
datalength = Convert.ToInt16(response[25 + commlength + miblength]);
datastart = 26 + commlength + miblength;
output = Encoding.ASCII.GetString(response, datastart, datalength);
if (output.StartsWith("MyDevice"))
{
callback(ihe.AddressList[0]);
}
}
}
Your issue is that you are iterating a none thread safe item the List.
If you replace it with a thread safe object like the ConcurrentBag you should find the threads will run in parallel.
I was a bit confused as to why this was only running one thread, I believe it is this line of code:
try
{
ihe = Dns.Resolve(host);
}
catch (Exception)
{
return;
}
I think this is throwing exceptions and returning; hence you only see one thread. This also ties into your observation that if you added a sleep it worked correctly.
Remember that when you pass a string your passing the reference to the string in memory, not the value. Anyway, the ConcurrentBag seems to resolve your issue. This answer might also be relevant
I'm trying to write a small application that simply reads data from a socket, extracts some information (two integers) from the data and sends the extracted information off on a serial port.
The idea is that it should start and just keep going. In short, it works, but not for long. After a consistently short period I start to receive IOExceptions and socket receive buffer is swamped.
The thread framework has been taken from the MSDN serial port example.
The delay in send(), readThread.Join(), is an effort to delay read() in order to allow serial port interrupt processing a chance to occur, but I think I've misinterpreted the join function. I either need to sync the processes more effectively or throw some data away as it comes in off the socket, which would be fine. The integer data is controlling a pan tilt unit and I'm sure four times a second would be acceptable, but not sure on how to best acheive either, any ideas would be greatly appreciated, cheers.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static bool _continue;
static SerialPort _serialPort;
static Thread readThread;
static Thread sendThread;
static String sendString;
static Socket s;
static int byteCount;
static Byte[] bytesReceived;
// synchronise send and receive threads
static bool dataReceived;
const int FIONREAD = 0x4004667F;
static void Main(string[] args)
{
dataReceived = false;
readThread = new Thread(Read);
sendThread = new Thread(Send);
bytesReceived = new Byte[16384];
// Create a new SerialPort object with default settings.
_serialPort = new SerialPort("COM4", 38400, Parity.None, 8, StopBits.One);
// Set the read/write timeouts
_serialPort.WriteTimeout = 500;
_serialPort.Open();
string moveMode = "CV ";
_serialPort.WriteLine(moveMode);
s = null;
IPHostEntry hostEntry = Dns.GetHostEntry("localhost");
foreach (IPAddress address in hostEntry.AddressList)
{
IPEndPoint ipe = new IPEndPoint(address, 10001);
Socket tempSocket =
new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
tempSocket.Connect(ipe);
if (tempSocket.Connected)
{
s = tempSocket;
s.ReceiveBufferSize = 16384;
break;
}
else
{
continue;
}
}
readThread.Start();
sendThread.Start();
while (_continue)
{
Thread.Sleep(10);
;// Console.WriteLine("main...");
}
readThread.Join();
_serialPort.Close();
s.Close();
}
public static void Read()
{
while (_continue)
{
try
{
//Console.WriteLine("Read");
if (!dataReceived)
{
byte[] outValue = BitConverter.GetBytes(0);
// Check how many bytes have been received.
s.IOControl(FIONREAD, null, outValue);
uint bytesAvailable = BitConverter.ToUInt32(outValue, 0);
if (bytesAvailable > 0)
{
Console.WriteLine("Read thread..." + bytesAvailable);
byteCount = s.Receive(bytesReceived);
string str = Encoding.ASCII.GetString(bytesReceived);
//str = Encoding::UTF8->GetString( bytesReceived );
string[] split = str.Split(new Char[] { '\t', '\r', '\n' });
string filteredX = (split.GetValue(7)).ToString();
string filteredY = (split.GetValue(8)).ToString();
string[] AzSplit = filteredX.Split(new Char[] { '.' });
filteredX = (AzSplit.GetValue(0)).ToString();
string[] ElSplit = filteredY.Split(new Char[] { '.' });
filteredY = (ElSplit.GetValue(0)).ToString();
// scale values
int x = (int)(Convert.ToInt32(filteredX) * 1.9);
string scaledAz = x.ToString();
int y = (int)(Convert.ToInt32(filteredY) * 1.9);
string scaledEl = y.ToString();
String moveAz = "PS" + scaledAz + " ";
String moveEl = "TS" + scaledEl + " ";
sendString = moveAz + moveEl;
dataReceived = true;
}
}
}
catch (TimeoutException) {Console.WriteLine("timeout exception");}
catch (NullReferenceException) {Console.WriteLine("Read NULL reference exception");}
}
}
public static void Send()
{
while (_continue)
{
try
{
if (dataReceived)
{
// sleep Read() thread to allow serial port interrupt processing
readThread.Join(100);
// send command to PTU
dataReceived = false;
Console.WriteLine(sendString);
_serialPort.WriteLine(sendString);
}
}
catch (TimeoutException) { Console.WriteLine("Timeout exception"); }
catch (IOException) { Console.WriteLine("IOException exception"); }
catch (NullReferenceException) { Console.WriteLine("Send NULL reference exception"); }
}
}
}
}
UPDATE:
Thanks for the response Jon.
What I'm attempting to do is poll a socket for data, if its there process it and send it to the serial port, else keep polling the socket , repeating this whole process ad nauseum.
My initial attempt used a single thread and I was getting the same problem, which led me to believe that I need to give the serial port some more time to allow it to send the data before giving it more data on the next loop, because once I've sent data to the serial port I'm back polling the socket very hard. Having said that IOExceptions occur after approximately 30 seconds of operation, possibly with what I'm saying is I should see IOExceptions immediately?
My interpretation of the join function, I think, is incorrect, ideally calling readThread.Join from send() would allow read() to sleep while still pumping the COM port, but where I have it seems to put the send() to sleep, which I guess is the calling function?? and not producing the desired result.
I've encountered this problem recently as well (and a lot of others have too) - and it's basically a problem with Microsoft's serial port initialization code. I've written a very detailed explanation here if you wish to find out more. I've also suggested a workaround. Hopefully there's enough fuss about this issue such that Microsoft would take notice and fix it asap - perhaps a .NET 4.0 hotfix. This issue has been going on long enough starting .NET 2.0 (first time System.IO.Ports namespace was introduced).
It looks like what you're trying to do is send some data, then wait for a response, then repeat. You're using two threads for this and trying to sync them. I think you only need one thread. First send, then wait for a response, then repeat. This will eliminate your thread sync problems.
I'm using visual studio to program this small TcpServer.
It's really specific. The server listens to port 1234 and is located on IP 127.0.0.1
Our teachers gave us a program that tries to connect to that port on that IP when you click "connect". It's working for everyone else, so it must be a coding error on my part.
When I click connect, the program sends the word "GET" over the stream, to which I have to respons with a list of allready connected IP-adress and then a newline containing only a .
When I disconnect, the program sends the word "REM" and I simply have to remove if from my list(which is a generic list)
I have a class TCPServer(we had to make our own), which has this as main code:
this.tl = new TcpListener(IPAddress.Any, PORT);
tl.Start();
while(true)
{
TcpClient tcl = tl.AcceptTcpClient();//here the server will wait forever untill someone connects, meaning the "new Thread" statement is never reached untill someone connects.
TcpHelper th = new TcpHelper(tcl,conf);
new Thread(new ThreadStart(th.Start)).Start();//should be multi-threaded, not sure if it is.
//t.Start();
}
TcpHelper looks like this(look for the commented text "here's the problem" within the usings):
public class TcpHelper
{
private TcpClient tc;
private IPEndPoint ipe;
private string get;
private Configuration conf;
public TcpHelper(TcpClient tc, Configuration conf)
{
this.tc = tc;
this.conf = conf;
}
public void Start()
{
using (NetworkStream nws = this.tc.GetStream())
{
using (StreamReader sr = new StreamReader(nws))
{
using (StreamWriter sw = new StreamWriter(nws))
{
this.ipe = (IPEndPoint)tc.Client.RemoteEndPoint;
this.conf.List.Add(this.ipe.Address);
bool conn = true;
while (conn)
{
this.get = sr.ReadLine();//here's the problem
switch (this.get)
{
case "GET":
foreach (IPAddress address in this.conf.Lijst)
{
sw.WriteLine(address.ToString());
}
sw.WriteLine(".");
break;
case "REM":
this.conf.List.Remove(this.ipe.Address);
sw.WriteLine("OK.");
conn = false;
break;
default:
break;
}
}
}
}
}
}
#region Properties
public IPEndPoint Ipe
{
get
{
return this.ipe;
}
}
#endregion
}
My guess is that your problem is that you're calling sr.ReadLine(), but the input does not contain a newline, so it's blocked there waiting for a newline that will never come.
you may want to try calling StreamReader.Read 3 times to build up the command string (GET/REM) before you act on it. (Note: 3 times is because all commands are three characters).
Read will return integers, but after checking that they are not -1 (indicating end-of-file), you can cast that integer to a char.
Sorry, maybe I'm not understanding this... Did you write this code?
this.tl = new TcpListener(IPAddress.Any, PORT);
tl.Start();
while(true)
{
TcpClient tcl = tl.AcceptTcpClient();
TcpHelper th = new TcpHelper(tcl,conf);
new Thread(new ThreadStart(th.Start)).Start();
//t.Start();
}
This is going to blow the **** out of any computer. You're looping infinitely, creating new threads on each loop. So, if you create one new thread per loop, and each loop takes one millisecond (lets say its very slow!), in five seconds you've got 5,000 threads. Each trying to listen at the same port.
Try using a single thread. If this is a console app, use Console.ReadLine() to block the main thread until somebody presses the enter key.
With the new information... AcceptTcpClient blocks, but instead of creating a new thread the work should be queued on the ThreadPool.