我已经开始构建一个tcp服务器,它将能够接受许多客户端,并同时从所有客户端接收新数据。
到目前为止,我使用IOCP用于tcp服务器,非常简单和舒适, 但这次我想使用Async / Await技术。这是在C#5.0中发布的。
问题在于,当我开始使用async / await编写服务器时,我发现在tcp中有多个用户服务器用例,async / await tech。常规同步方法也是一样的。
这是一个更具体的简单示例:
class Server
{
private TcpListener _tcpListener;
private List<TcpClient> _clients;
private bool IsStarted;
public Server(int port)
{
_tcpListener = new TcpListener(new IPEndPoint(IPAddress.Any, port));
_clients = new List<TcpClient>();
IsStarted = false;
}
public void Start()
{
IsStarted = true;
_tcpListener.Start();
Task.Run(() => StartAcceptClientsAsync());
}
public void Stop()
{
IsStarted = false;
_tcpListener.Stop();
}
private async Task StartAcceptClientsAsync()
{
while (IsStarted)
{
// ******** Note 1 ********
var acceptedClient = await _tcpListener.AcceptTcpClientAsync();
_clients.Add(acceptedClient);
IPEndPoint ipEndPoint = (IPEndPoint) acceptedClient.Client.RemoteEndPoint;
Console.WriteLine("Accepted new client! IP: {0} Port: {1}", ipEndPoint.Address, ipEndPoint.Port);
Task.Run(() => StartReadingDataFromClient(acceptedClient));
}
}
private async void StartReadingDataFromClient(TcpClient acceptedClient)
{
try
{
IPEndPoint ipEndPoint = (IPEndPoint) acceptedClient.Client.RemoteEndPoint;
while (true)
{
MemoryStream bufferStream = new MemoryStream();
// ******** Note 2 ********
byte[] buffer = new byte[1024];
int packetSize = await acceptedClient.GetStream().ReadAsync(buffer, 0, buffer.Length);
if (packetSize == 0)
{
break;
}
Console.WriteLine("Accepted new message from: IP: {0} Port: {1}\nMessage: {2}",
ipEndPoint.Address, ipEndPoint.Port, Encoding.Default.GetString(buffer));
}
}
catch (Exception)
{
}
finally
{
acceptedClient.Close();
_clients.Remove(acceptedClient);
}
}
}
现在,如果您看到“注1”和“注2”下的行, 它可以很容易地改为:
来自
的注1var acceptedClient = await _tcpListener.AcceptTcpClientAsync();
到
var acceptedClient = _tcpListener.AcceptTcpClient();
来自
的注2int packetSize = await acceptedClient.GetStream().ReadAsync(buffer, 0, 1024);
到
int packetSize = acceptedClient.GetStream().Read(buffer, 0, 1024);
服务器将完全相同。
那么,为什么在tcp监听器中为多个用户使用async / await,如果它与使用常规同步方法一样?
在这种情况下我应该继续使用IOCP吗?因为对我来说这非常容易和舒适,但我担心它会被淘汰,甚至在较新的.NET版本中也不再可用。
答案 0 :(得分:17)
直到现在,我使用IOCP用于tcp服务器,这非常简单和舒适,但这次我想使用Async / Await技术。这是在C#5.0中发布的。
我认为你需要正确的术语。
将BeginOperation
和EndOperation
方法称为Asynchronous Programming Model(APM)。使用单个Task
(或Task<T>
)返回方法称为Task-based Asynchronous Pattern(TAP)。 I/O Completion Ports(IOCP)是一种在Windows上处理异步操作的方法,使用两者 APM和TAP使用它们的异步I / O方法。
这意味着APM和TAP的性能将非常相似。两者之间的最大区别在于使用TAP和async
- await
的代码比使用APM和回调的代码更具可读性。
因此,如果您想(或必须)异步编写代码,请使用TAP和async
- await
,如果可以的话。但如果你没有充分的理由这样做,只需同步编写你的代码。
在服务器上,使用异步的一个很好的理由是可伸缩性:异步代码可以同时处理更多的请求,因为它往往使用更少的线程。如果您不关心可伸缩性(例如,因为您不会同时拥有多个用户),那么异步并没有多大意义。
此外,您的代码包含一些您应该避免的做法:
async void
方法,没有好的方法来判断它们何时完成并且它们有异常处理。例外是事件处理程序,但这主要适用于GUI应用程序。Task.Run()
。如果要保留当前线程(通常是UI线程)或者要并行执行同步代码,Task.Run()
会很有用。但是使用它在服务器应用程序中启动异步操作没有多大意义。Task
,除非您确定它们不会抛出异常。忽略Task
的例外情况不会做任何事情,这很容易掩盖错误。答案 1 :(得分:1)
经过几次搜索,我找到了this
问:这是TCPServer实践列表,但哪一个是每秒管理5000多个客户端的最佳做法?
A :我的假设是&#34; 编写异步方法&#34;如果你同时使用数据库&#34; 异步方法和迭代器&#34;会做更多的事情
答案 2 :(得分:0)