异步/等待或开始/结束使用的TcpListener? [英] async / await or Begin / End with TcpListener?

查看:315
本文介绍了异步/等待或开始/结束使用的TcpListener?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经开始建立一个TCP服务器,将能够接受许多客户,并同时从所有的客户端接收新的数据。

到现在为止,我用了IOCP这是pretty的方便和舒适的TCP服务器, 但这次我想使用异步/等待技术。这是发布在C#5.0。

现在的问题是,当我开始写使用异步服务器/计谋,我想通了,在TCP多个用户的服务器使用的情况下,异步/计谋技术。和普通同步方法将工作一样。

下面是一个简单的例子来更具体:

 类服务器
{
    私人的TcpListener _tcpListener;
    私人列表< TcpClient的> _clients;
    私人布尔IsStarted;

    公共服务器(INT端口)
    {
        _tcpListener =新的TcpListener(新IPEndPoint(IPAddress.Any,口));
        _clients =新的名单,其中,TcpClient的>();
        IsStarted = FALSE;
    }

    公共无效启动()
    {
        IsStarted = TRUE;
        _tcpListener.Start();
        Task.Run(()=> StartAcceptClientsAsync());
    }

    公共无效停止()
    {
        IsStarted = FALSE;
        _tcpListener.Stop();
    }

    私人异步任务StartAcceptClientsAsync()
    {
        而(IsStarted)
        {
            // ********注1 ********
            VAR acceptedClient =等待_tcpListener.AcceptTcpClientAsync();

            _clients.Add(acceptedClient);
            IPEndPoint ipEndPoint =(IPEndPoint)acceptedClient.Client.RemoteEndPoint;
            Console.WriteLine(接受新的客户端IP:{0}端口:{1},ipEndPoint.Address,ipEndPoint.Port);

            Task.Run(()=> StartReadingDataFromClient(acceptedClient));
        }
    }

    私人异步无效StartReadingDataFromClient(TcpClient的acceptedClient)
    {
        尝试
        {
            IPEndPoint ipEndPoint =(IPEndPoint)acceptedClient.Client.RemoteEndPoint;
            而(真)
            {
                MemoryStream的bufferStream =新的MemoryStream();
                // ********注2 ********
                byte []的缓冲区=新的字节[1024];
                INT PACKETSIZE =等待acceptedClient.GetStream()ReadAsync(缓冲,0,buffer.Length)。

                如果(PACKETSIZE == 0)
                {
                    打破;
                }

                Console.WriteLine(接受新信息:IP:{0}端口:{1} \ n消息:{2},
                    ipEndPoint.Address,ipEndPoint.Port,Encoding.Default.GetString(缓冲液));
            }
        }
        赶上(例外)
        {
        }
        最后
        {
            acceptedClient.Close();
            _clients.Remove(acceptedClient);
        }
    }
}
 

现在,如果你看到在注1和注2的行, 它可以很容易地变更为:

注1从

  VAR acceptedClient =等待_tcpListener.AcceptTcpClientAsync();
 

  VAR acceptedClient = _tcpListener.AcceptTcpClient();
 

和从

请注意2

  INT PACKETSIZE =等待acceptedClient.GetStream()ReadAsync(缓冲,0,1024)。
 

  INT PACKETSIZE = acceptedClient.GetStream()读取(缓冲,0,1024)。
 

和服务器将工作完全一样的。

那么,为什么要使用异步/等候在TCP监听器为多个用户,如果它同样喜欢使用常规的同步方法?

我要保持在这种情况下,使用完成端口?,因为对于我来说,pretty的方便和舒适,但我很担心它会过时,甚至没有更多的新的.NET版本。

解决方案
  

直到如今,我用IOCP为这是pretty的方便和舒适的TCP服务器,但这个时候,我想使用异步/等待技术。这是发布在C#5.0。

我想你需要得到您的术语的权利。

BeginOperation EndOperation 方法被调用的Asynchronous编程模型(APM)。有一个工作(或任务< T> )返回方法被调用的Task-based异步模式(TAP)。 I / O完成端口(IOCP)是一种方法,在处理异步操作使用Windows和异步I / O方法的两个的APM和TAP使用它们。

这句话的意思是,APM和TAP的表现将是非常相似的。两者之间最大的区别是使用TAP是code和异步 - 等待远远超过$更具可读性C $ c。使用APM和回调。

所以,如果你想(或必须)编写code异步,用自来水和异步 - 等待,如果可以的话。但是,如果你没有一个很好的理由这样做,只写你的code同步。

在服务器上,使用异步一个很好的理由是可伸缩性:异步code可以同时处理更多的请求,因为它往往使用较少的线程。如果你不关心的可扩展性(例如,因为你不会有很多用户在同一时间),然后异步并没有太大的意义。


另外,你的code包含一些做法,你应该避免:

  • 请不要使用异步无效方法,有没有什么好办法告诉当他们完成他们有坏的异常处理。唯一的例外是事件处理程序,但能适用于大部分的GUI应用程序。
  • 请不要使用 Task.Run()如果你没有。 Task.Run()如果你想离开当前线程(通常是UI线程),或者如果你想在并行执行同步code可能是有用的。但它并没有多大意义,用它来在服务器应用程序启动异步操作。
  • 请不要忽视工作 - 从方法返回,除非你确定他们不会抛出异常。从忽略工作取值例外不会做任何事情,它可以很容易地掩盖错误。

I've started to build a tcp server which will be able to accept many clients, and receive simultaneously from all of the clients new data.

Until now, I used IOCP for tcp servers which was pretty easy and comfortable, but this time I want to use the Async / Await tech. that was released in C# 5.0.

The problem is that when I started to write the server using async / await, I figured out that in tcp multiple users server use case, async / await tech. and the regular synchrony methods will work the same.

Here's a simple example to be more specific:

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);
        }
    }
}

Now if you see the lines under 'Note 1' and 'Note 2', It can easily be changed to:

Note 1 from

var acceptedClient = await _tcpListener.AcceptTcpClientAsync();

to

var acceptedClient = _tcpListener.AcceptTcpClient();

And Note 2 from

int packetSize = await acceptedClient.GetStream().ReadAsync(buffer, 0, 1024);

to

int packetSize = acceptedClient.GetStream().Read(buffer, 0, 1024);

And the server will work exactly the same.

So, why using async / await in tcp listener for multiple users if it's the same like using regular synchrony methods?

Should I keep using IOCP in that case? because for me it's pretty easy and comfortable but I am afraid that it will be obsoleted or even no more available in newer .NET versions.

解决方案

Untill now, i used IOCP for tcp servers which was pretty easy and comfortable, but this time i want to use the Async / Await tech. that was released in C# 5.0.

I think you need to get your terminology right.

Having BeginOperation and EndOperation methods is called Asynchronous Programming Model (APM). Having a single Task (or Task<T>) returning method is called Task-based Asynchronous Pattern (TAP). I/O Completion Ports (IOCP) are a way to handle asynchronous operations on Windows and asynchronous I/O methods using both APM and TAP use them.

What this means is that the performance of APM and TAP is going to be very similar. The big difference between the two is that code using TAP and async-await is much more readable than code using APM and callbacks.

So, if you want to (or have to) write your code asynchronously, use TAP and async-await, if you can. But if you don't have a good reason to do that, just write your code synchronously.

On the server, a good reason to use asynchrony is scalability: asynchronous code can handle many more requests at the same time, because it tends to use fewer threads. If you don't care about scalability (for example because you're not going to have many users at the same time), then asynchrony doesn't make much sense.


Also, your code contains some practices that you should avoid:

  • Don't use async void methods, there is no good way to tell when they complete and they have bad exception handling. The exception is event handlers, but that applies mostly to GUI applications.
  • Don't use Task.Run() if you don't have to. Task.Run() can be useful if you want to leave the current thread (usually the UI thread) or if you want to execute synchronous code in parallel. But it doesn't make much sense to use it to start asynchronous operations in server applications.
  • Don't ignore Tasks returned from methods, unless you're sure they're not going to throw an exception. Exceptions from ignored Tasks won't do anything, which could very easily mask a bug.

这篇关于异步/等待或开始/结束使用的TcpListener?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆