Search code examples
xamarintcplistener

how to make TCP server in xamarin that does not freeze my app


I have a TCP Server with an start method looking like :

public async Task Start()
{
    using (Canceler.Token.Register(() => listener.Stop()))
    {
        try
        {
            listener.Start();
            var tcpClient = await listener.AcceptTcpClientAsync();
            var clientStream = tcpClient.GetStream();
            while(!CloseAll)
            {
                while (!clientStream.DataAvailable)
                {
                    if (CloseAll)
                    {
                        break;
                    }
                }
                Byte[] bytes = new Byte[tcpClient.Available];
                clientStream.Read(bytes, 0, bytes.Length);
                String data = Encoding.UTF8.GetString(bytes);
                Debug(data);
            } 
        }
        catch (Exception exc)
        {
            Debug(exc.Message);
            Canceler.Token.ThrowIfCancellationRequested();
            throw;
        }
    }
}

And then the communication class that handles it goes like:

internal async void Init()
{
    DebugMessage("initializing gameBrain");
    TCP = new TCPController();
    TCP.newDebugMessage += Debug;
    await TCP.Start();
}

And at the topmost, in the page we have :

public MainPage(GameBrain _brain)
{
    InitializeComponent();
    Brain = _brain;
    Brain.newMessageToUI += NewMessageFromBrain;
    Brain.Init();
}

I ran the thing and it works at the beginning. The UI is responsive (I added a button with a displayAlert for testing) I noticed that the system freezes after the TCP client connects. In the inner while of the Start but ... I thought it was expected!

I thought the Start will run in a different thread while the app get's freed of it. To be honest I was used to backgroundworkers but I'm moving from there to Tasks, and there is clearly somethign I don't get.

How should that be done ?


Solution

  • In C#, async and await are used to allow code to keep executing while some asynchronous process is being done. This does not at all mean that you are starting a parallel process on another thread.

    When you call this:

    internal async void Init()
    {
        (..)
        await TCP.Start();
    }
    

    You are merely saying to the runtime that TCP.Start() will eventually have a point in the execution where some asynchronous process (like an HTTP request to a 3rd party) is started and that it is allowed to execute code after TCP.Start() instead of waiting for TCP.Start() to finish like a normal C# method is being treated.

    If you want TCP.Start() to be run in parallel, you should create a new Task in which you call the method like in the following code (I might have flunked on the proper syntax)

    internal async void Init()
    {
        (..)
        Task.Run(async () => await TCP.Start());
    }
    

    Now the TCP.Start() method will be executed in parallel to the rest of the application.

    Read more on async and await here