【问题标题】:UWP TCP receive data continuouslyUWP TCP 连续接收数据
【发布时间】:2017-09-20 00:25:29
【问题描述】:

我编写了一个 TCP 服务器应用程序,我可以在其中侦听专用端口上的传入连接。有了这个,我可以得到一个“连接”事件,然后接收数据(只有一次)。

如何从端口连续接收数据(也许还可以检测客户端是否仍然连接)?

我连接了一个 NodeMCU(基于 Arduino)系统,该系统使用 TCP 连接每秒发送一些温度数据。

通过 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;
}

处理新连接并接收数据的事件:

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

一旦建立连接,此代码可以完美地接收数据。

我正在考虑一种解决方案,一旦新数据在输入缓冲区中就获取事件,然后处理数据。

【问题讨论】:

    标签: c# sockets tcp uwp


    【解决方案1】:

    我正在考虑一种解决方案,一旦新数据在输入缓冲区中就获取事件,然后处理数据。

    在 UWP API 中没有可以在每次收到新日期时触发的此类事件。我们通常在这里做的是使用一个while循环来连续接收数据。例如,您可以在 LocalSocketConnectionReceived 方法中添加一个 while 循环,如下所示:

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

    while 循环在这里有效,因为Data​Reader.LoadAsync(UInt32) 是一个异步方法。如果没有收到日期,它将在那里等待。

    更多信息请参考GitHub上的StreamSocket sample,尤其是场景一中的OnConnection方法。

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

    【讨论】:

    • 我现在围绕这个主题工作,并且使用这种方法接收消息可以正常工作。当我关闭连接/服务器时,我总是在await reader.LoadAsync((uint)payloadSize.Length); 行中收到异常“System.ObjectDisposedException”,因为输入套接字已关闭。如何阻止 while 循环监听端口?
    猜你喜欢
    • 2020-02-24
    • 1970-01-01
    • 2017-08-05
    • 2016-12-16
    • 2014-09-06
    • 1970-01-01
    • 2017-05-24
    • 1970-01-01
    • 2021-04-04
    相关资源
    最近更新 更多