5

我有一个正在为 Windows 8/WinRT 编写的应用程序,它使用 StreamSocket API 与服务器进行流式连接。也就是说,服务器将数据流式传输到客户端,有时带有元标记,并且可以随时断开连接。

我遇到的问题是我不知道如何检测服务器何时断开连接。StreamSocket 类、其输入或输出流或 DataReader/DataWriter 类上似乎没有任何与连接状态有关的事件或属性。

最重要的是,在服务器端与客户端断开连接后,DataReader 方法 ReadAsync 不会失败。相反,据我所知,操作成功了,它填充到其缓冲区中的数据只是服务器发送给它的最后一件事(即它没有清除其内部缓冲区,即使我可以看到它已“消耗”每次调用 ReadByte 时的缓冲区)。它为每次对 ReadAsync 的后续调用执行此操作 - 用服务器在断开连接之前最后发送的内容重新填充缓冲区。这是代码的简化版本:

    public async Task TestSocketConnectionAsync()
    {
        var socket = new StreamSocket();
        await socket.ConnectAsync(new HostName(Host), Port.ToString(),
            SocketProtectionLevel.PlainSocket);
        var dr = new DataReader(socket.InputStream);
        dr.InputStreamOptions = InputStreamOptions.Partial;

        this.cts = new CancellationTokenSource();
        this.listenerOperation = StartListeningAsync(dr, cts);
    }

    public async Task StartListeningAsync(DataReader dr, CancellationTokenSource cts)
    {
        var token = cts.Token;
        while (true)
        {
            token.ThrowIfCancellationRequested();
            var readOperation = dr.LoadAsync(1024);
            var result = await readOperation;
            if (result <= 0 || readOperation.Status != Windows.Foundation.AsyncStatus.Completed)
            {
                cts.Cancel(); // never gets called, status is always Completed, result always > 0
            }
            else
            {
                while (dr.UnconsumedBufferLength > 0)
                {
                    byte nextByte = dr.ReadByte();

                    // DriveStateMachine(nextByte);
                }
            }
        }
    }
4

1 回答 1

9

也就是说,服务器将数据流式传输到客户端,有时带有元标记,并且可以随时断开连接。我遇到的问题是我不知道如何检测服务器何时断开连接。

另一端可以将“优雅的”套接字关闭检测为 0 长度读取。也就是说,它就像一个常规的流结束。

“失败的”套接字关闭更加棘手。您必须发送数据以检测对方已关闭,并且一旦写入失败,任何额外的读取或写入都应该失败(有例外)。如果您的协议不允许您发送数据,那么您将不得不在超时到期后假设连接不良并关闭它。:(

根据应用程序,“中止”套接字关闭可能是正常的 - 特别是,可能会编写非常繁忙的服务器来钳制关闭它们的连接,因为它允许它们更快地回收资源(避免步套接字关闭握手)。

StreamSocket 类、其输入或输出流或 DataReader/DataWriter 类上似乎没有任何与连接状态有关的事件或属性。

DataReader/DataWriter不关心“连接”。他们真的只是BitConverter,只是这次设计得更好。

我猜想StreamSocket没有“连接”属性的原因是因为Socket.Connected几乎没用而且绝对是误导性的。


我会尝试StreamSocket.InputStream.ReadAsync直接使用而不是使用DataReader,因为无论如何你只是在读取字节。听起来您可能在 中发现了一个错误,如果按预期工作,您应该在Microsoft ConnectDataReader上报告该错误。另请参阅此相关论坛帖子InputStream.ReadAsync

于 2012-04-11T01:39:58.757 回答