Trying to create an async tcp server. Previously I could accomplish this with Begin/End pattern pretty good and handle multiple clients like this:
class Server
{
IPEndPoint ipep;
TcpListener listener;
bool Running;
List<Client> clients;
public Server(string host)
{
IPAddress ip = IPAddress.Parse(host);
ipep = new(ip, 21);
Running = false;
clients = new();
}
public void Start()
{
listener = new(ipep);
listener.Start();
Running = true;
while (Running)
listener.BeginAcceptTcpClient(Accept, null);
}
public void Accept(IAsyncResult ar)
{
Client client = new(listener.EndAcceptTcpClient(ar));
clients.Add(client);
client.WaitCommands();
}
}
class Client
{
TcpClient client;
NetworkStream stream;
public Client(TcpClient client)
{
this.client = client;
stream = client.GetStream();
}
public void WaitCommands()
{
stream.BeginRead(/*some buffer stuff*/, Receive, null);
}
public void Receive(IAsyncResult ar)
{
stream.EndRead(ar);
stream.BeginRead(/*again buffer stuff*/, Receive, null);
}
}
and there are a lot of examples of this in the Internet. But MSDN seems to recommend using async methods instead, so I wanna convert to it. Here's what I have:
class Server
{
IPEndPoint ipep;
TcpListener listener;
bool Running;
List<Client> clients;
public Server(string host)
{
IPAddress ip = IPAddress.Parse(host);
ipep = new(ip, 21);
Running = false;
clients = new();
}
public async Task Start()
{
listener = new(ipep);
listener.Start();
Running = true;
while (Running)
{
Client c = await listener.AcceptTcpClientAsync();
clients.Add(c);
await c.WaitCommands();
}
}
}
class Client
{
TcpClient client;
NetworkStream stream;
public Client(TcpClient client)
{
this.client = client;
stream = client.GetStream();
}
public async Task WaitCommands()
{
while (true)
{
await stream.ReadAsync(/*buffer stuff*/);
}
}
}
and obviously await c.WaitCommands();
blocks other clients, since app is stuck in while (true) loop and never reaches await Accept again. I found some that _ = Task.Run(async () => await client.WaitCommands());
does the trick. But as I understood that takes threads from threadpool, unlike Begin/End approach (or am I wrong? that's the question too).
So the questions are
- How to start reading from client and accept another ones in the second example?
- Am I going the right way? Or what approach should be used for most user-count scale (i.e. maybe should I go some threads per client instead)?