【发布时间】:2022-01-01 19:03:08
【问题描述】:
尝试创建异步 tcp 服务器。 以前我可以使用 Begin/End 模式很好地完成此操作,并像这样处理多个客户端:
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);
}
}
互联网上有很多这样的例子。但是 MSDN 似乎建议使用异步方法,所以我想转换为它。这是我所拥有的:
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*/);
}
}
}
显然await c.WaitCommands(); 会阻止其他客户端,因为应用程序卡在 while (true) 循环中并且永远不会再次到达 await Accept。我发现一些 _ = Task.Run(async () => await client.WaitCommands()); 可以解决问题。但据我了解,这与 Begin/End 方法不同(或者我错了吗?这也是问题所在)。
所以问题是
- 如何在第二个示例中从客户端开始读取并接受另一个?
- 我走对了吗?或者对于大多数用户计数规模应该使用什么方法(即,也许我应该为每个客户端使用一些线程)?
【问题讨论】:
-
在接受循环中,您不应等待客户端完成。为接受循环使用一个线程并为每个客户端使用一个新线程是一种简单的模型,并且可以很好地扩展到数百个客户端。
-
@DavidBrowne-Microsoft 是的,这就是我所理解的,但是如何使用异步方法?第一个带有回调的例子效果很好,但我不知道如何用 async/await 做同样的事情,或者我什至应该像 MSDN 建议的那样做
标签: c# asynchronous tcp networkstream