UWP TCP receive data continuously

南楼画角 提交于 2019-12-25 09:27:23

问题


I've programmed a TCP server application where I can listen to incoming connections on a dedicated port. With this I'm able to get an "connected" event and then receive data (only once).

How can I receive data continuously from the port (and maybe also detect if the client is still connected)?

I've connected a NodeMCU (Arduino based) system which sends some temperature data every second using the TCP connection.

Starting and stopping the server through a toggle switch in the UI:

public async Task<bool> StartListeningAsync()
{
    if (TCPSocket == null)
    {
        TCPSocket = new StreamSocketListener();
        TCPSocket.ConnectionReceived += LocalSocketConnectionReceived;
        await TCPSocket.BindServiceNameAsync(CommunicationPort);
        return true;
    }
    return false;
}

public async Task<bool> StopListening()
{
    if (connectedSocket != null)
    {
        connectedSocket.Dispose();
        connectedSocket = null;
    }

    if (TCPSocket != null)
    {
        await TCPSocket.CancelIOAsync();
        TCPSocket.ConnectionReceived -= LocalSocketConnectionReceived;
        TCPSocket.Dispose();
        TCPSocket = null;
        return true;
    }

    return false;
}

Event that handles a new connection and receive data:

private async void LocalSocketConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
    if (connectedSocket != null)
    {
        connectedSocket.Dispose();
        connectedSocket = null;
    }
    connectedSocket = args.Socket;


    await textBox_send.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        textBox_send.IsEnabled = true;
        txtConnected.Text = "Client Connected";
    });

    using (var reader = new DataReader(args.Socket.InputStream))
    {
        await readTCPDataAsync(reader);
    }

}

private async Task readTCPDataAsync(DataReader reader)
{            
    reader.InputStreamOptions = InputStreamOptions.None;

    // Read the length of the payload that will be received.
    byte[] payloadSize = new byte[(uint)BitConverter.GetBytes(0).Length];
    await reader.LoadAsync((uint)payloadSize.Length);
    reader.ReadBytes(payloadSize);


    // Read the payload.
    int size = BitConverter.ToInt32(payloadSize, 0);
    //size = 2;
    byte[] payload = new byte[size];
    await reader.LoadAsync((uint)size);
    reader.ReadBytes(payload);

    string data = Encoding.ASCII.GetString(payload);
}

This code works perfectly to receive the data once the connection is established.

I'm thinking of a solution to get an event once new data is on the input buffer and then process the data.


回答1:


I'm thinking of a solution to get an event once new data is on the input buffer and then process the data.

There is no such event in UWP API that can be triggered at each time a new date is received. What we usually do here is using a while loop to receive data continuously. For example, you can add a while loop in your LocalSocketConnectionReceived method like the following:

using (var reader = new DataReader(args.Socket.InputStream))
{
    while (true)
    {
        await readTCPDataAsync(reader);
    }
}

The while loop works here because Data​Reader.LoadAsync(UInt32) is a asynchronous method. It will wait there if there is no date received.

For more info, please refer to the StreamSocket sample on GitHub, especially the OnConnection method in Scenario 1.

/// <summary>
/// Invoked once a connection is accepted by StreamSocketListener.
/// </summary>
/// <param name="sender">The listener that accepted the connection.</param>
/// <param name="args">Parameters associated with the accepted connection.</param>
private async void OnConnection(
    StreamSocketListener sender, 
    StreamSocketListenerConnectionReceivedEventArgs args)
{
    DataReader reader = new DataReader(args.Socket.InputStream);
    try
    {
        while (true)
        {
            // Read first 4 bytes (length of the subsequent string).
            uint sizeFieldCount = await reader.LoadAsync(sizeof(uint));
            if (sizeFieldCount != sizeof(uint))
            {
                // The underlying socket was closed before we were able to read the whole data.
                return;
            }

            // Read the string.
            uint stringLength = reader.ReadUInt32();
            uint actualStringLength = await reader.LoadAsync(stringLength);
            if (stringLength != actualStringLength)
            {
                // The underlying socket was closed before we were able to read the whole data.
                return;
            }

            // Display the string on the screen. The event is invoked on a non-UI thread, so we need to marshal
            // the text back to the UI thread.
            NotifyUserFromAsyncThread(
                String.Format("Received data: \"{0}\"", reader.ReadString(actualStringLength)), 
                NotifyType.StatusMessage);
        }
    }
    catch (Exception exception)
    {
        // If this is an unknown status it means that the error is fatal and retry will likely fail.
        if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
        {
            throw;
        }

        NotifyUserFromAsyncThread(
            "Read stream failed with error: " + exception.Message, 
            NotifyType.ErrorMessage);
    }
}


来源:https://stackoverflow.com/questions/43569161/uwp-tcp-receive-data-continuously

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!