【发布时间】:2018-08-08 16:45:12
【问题描述】:
我想在 .NET Core 2.0 中使用 async/await 方法使用异步(因为据我了解,它比生成线程更合理)(因为我相信它比具有IAsyncResult 和*Begin/*End 方法的那个)。
我编写了这个小型服务器,它接受来自客户端的新连接,然后开始向它们发送 100 条消息(它们之间有 1 秒的延迟)。
主要问题是:
如果我没有产生新线程,那么服务器如何继续向多个客户端发送延迟消息,而实际上它是“等待连接”? 是否涉及任何隐藏的低级信号/事件,或者真的只是新线程?
第二个问题是:
如果我没有使用这个全新的 async Main 语法糖并且我没有“等待”发送消息的 async 任务——我是否正确使用了异步?
class Program
{
public static void Main(string[] args)
{
StartServer();
}
public static void StartServer()
{
IPAddress localhost = IPAddress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(localhost, 5567);
Console.WriteLine($"Starting listening on {listener.Server.LocalEndPoint}");
listener.Start();
while (true)
{
Console.WriteLine("Waiting for connection...");
var client = listener.AcceptTcpClient(); // synchronous
Console.WriteLine($"Connected with {client.Client.RemoteEndPoint}!");
Console.WriteLine("Starting sending messages...");
SendHundredMessages(client); // not awaited -- StartServer is not async
}
}
public static async Task SendHundredMessages(TcpClient client)
{
var stream = client.GetStream();
for (int i=0; i<100; i++)
{
var msg = Encoding.UTF8.GetBytes($"Message no #{i}\n");
await stream.WriteAsync(msg, 0, msg.Length); // returning back to caller?
await Task.Delay(1000); // and what about here?
}
client.Close();
}
}
原代码和下面的版本有什么区别? async Main 有什么不同?
class Program
{
public static async Task Main(string[] args)
{
await StartServer();
}
public static async Task StartServer()
{
IPAddress localhost = IPAddress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(localhost, 5567);
Console.WriteLine($"Starting listening on {listener.Server.LocalEndPoint}");
listener.Start();
while (true)
{
Console.WriteLine("Waiting for connection...");
var client = await listener.AcceptTcpClientAsync(); // does it make any difference when done asynchronously?
Console.WriteLine($"Connected with {client.Client.RemoteEndPoint}!");
Console.WriteLine("Starting sending messages...");
SendHundredMessages(client); // cannot await here, because it blocks next connections
}
}
public static async Task SendHundredMessages(TcpClient client)
{
var stream = client.GetStream();
for (int i=0; i<100; i++)
{
var msg = Encoding.UTF8.GetBytes($"Message no #{i}\n");
var result = stream.WriteAsync(msg, 0, msg.Length);
await Task.Delay(1000);
await result;
}
client.Close();
}
}
【问题讨论】:
-
为什么
StartServerasync Task没有await什么?你至少应该使用await listener.AcceptTcpClientAsync(); -
因为我之前在
async Main中尝试过await StartServer()并且(失败后)我忘记将这个方法的类型改回void。 -
如果我
await和AcceptTcpClientAsync()没有将void Main更改为async Task Main和StartServer();到await StartServer();则程序到此结束。另一方面——当调用者只是这个几乎是空的 Main 方法时,等待 Accept 的目的是什么? -
因为
AcceptTcpClient是一种I/O 有界方法(如stream.WriteAsync),因此是真正的异步方法,它从异步代码中获益最多。谁叫它并不重要。您应该在Main上阻止StartServer并将其保留为async Task -
@CamiloTerevinto 我编辑了原始代码(您提到的 StartServer 类型)。在您添加评论之前,我还添加了一个后续问题。如果服务器目前什么都不做,Accept 异步有什么好处?
标签: c# tcp server async-await .net-core