I have the following code which I want to implement as my server. As I understand it is async. and should allow connections from multiple clients...
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
while (true)
{
IAsyncResult res = listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
connectionWaitHandle.WaitOne();
}
}
private void HandleAsyncConnection(IAsyncResult res)
{
TcpListener listener = (TcpListener)res.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(res);
connectionWaitHandle.Set();
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
I have a test app which simply fires requests to my server. As you can see in the code the server just replies with its date/time. The test app sends say 20 requests which are simply test strings. For each of these requests it opens a socket, sends the data to my server and then closes the socket again.
This works fine with one test app running. However, if I open two test apps the second one cannot connect to the server. I thought because I am handling the request async. and because my test app opens then closes the socket before each call I could handle requests from multiple clients?
The way you did it, there is no benefit compared to using AcceptTcpClient
. Simply loop and create a new thread for each accepted connection:
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
while (canRun)
{
var client = listener.AcceptTcpClient();
new Thread(ClientThread).Start(client);
}
}
private void ClientThread(IAsyncResult res)
{
TcpClient client = (TcpClient)res.AsyncState;
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
A golden rule when using asynchronous methods is to NOT block the operation. Blocking would defeat the purpose of using async ops.
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
listener.BeginAcceptTcpClient(OnAccept, listener);
}
private void OnAccept(IAsyncResult res)
{
TcpListener listener = (TcpListener)res.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(res);
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
If using >=.Net4.5, it's better to use the new network methods that then permit the adoption of async
and await
. As such, it might be better to follow the example I provided in this post as a starting point.
The following code demonstrates how to accept multiple clients asynchronously without spinning off a new thread per connection.
private TcpListener listener;
public void Start()
{
listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
StartAccept();
}
private void StartAccept()
{
listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
}
private void HandleAsyncConnection(IAsyncResult res)
{
StartAccept(); //listen for new connections again
TcpClient client = listener.EndAcceptTcpClient(res);
//proceed
}
You can use this pattern for most async operations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With