【问题标题】:Leave open a StreamReader in Unity c#在 Unity c# 中打开一个 StreamReader
【发布时间】:2015-08-27 08:12:08
【问题描述】:

我正在开发一个游戏,我需要从流(尚未结束)中检索数据。

我有一个名为 StreamingChannel 的类,它创建了流媒体频道

    public StreamingChannel (){

    //stuff to set the stream

    webResponse = (HttpWebResponse) webRequest.GetResponse();
    responseStream = new StreamReader (webResponse.GetResponseStream (), encode);
    }

并从中读取我有这个方法

public string Read(){

    try{
        string jsonText = responseStream.ReadLine();
        return jsonText;
    }catch(ObjectDisposedException){
        return null;
    }
}

我使用 InvokeRepeating 每隔几秒执行一次读取,并且在整个游戏中都这样做。

效果很好,只是我的直播持续了大约几分钟。之后它会抛出一个 ObjectDisposedException。

起初我想恢复连接,但如果不重新实例化整个连接,我就无法做到。在这种情况下,问题是游戏延迟了大约一秒钟。 那么如何告诉 StreamReader 必须保持打开通道?

ps 我不能使用构造函数

public StreamReader(
Stream stream,
Encoding encoding,
bool detectEncodingFromByteOrderMarks,
int bufferSize,
bool leaveOpen)

因为它已在 .NET Framework 4.5 版本中引入,而 Unity 不支持。

【问题讨论】:

  • 你确定是 StreamReader 被处理了吗?如果你在ObjectDisposedException 上调用ToString() 会返回什么?
  • 其实我不太确定(我对此很陌生)。经过一番谷歌搜索后,我得出了这个结论。无论如何,我在 Read() 方法的 catch 子句中添加了这条指令: Debug.Log("myself " + ToString() + " webresponse " + webResponse.ToString() + " responsestream " + responseStream.ToString());输出是:我自己为空 webresponse System.Net.HttpWebResponse responsestream System.IO.StreamReader
  • 将 catch(ObjectDisposedException){ 更改为 catch(ObjectDisposedException e){ 并将 Debug.Log("exception: " + e) 添加到您的 catch 块中。
  • 它说:异常:System.ObjectDisposedException:对象在被释放后被使用。
  • Debug.Log("stack: " + e.StackTrace) 怎么样?

标签: c# unity3d stream streamreader


【解决方案1】:

流式 API 期望您的代码非常积极地从 Stream 中提取数据。您可能无法等待 Unity 安排您的 ReadLine 方法。我认为更好的模型是使用单独的线程尽可能快地从 Stream 中提取数据并将其存储在缓冲区中。 (我认为这在 Unity 中是可能的。) 然后您可以在标准 Unity 线程中将流数据从缓冲区中拉出,而不必担心拉取率。 ConcurrentQueue 会是一个很好的缓冲区,但 Unity 不支持它,所以我使用了一个锁定的 List。

使用单独的线程还可以让您在失败后重新启动,而不会阻塞主游戏。

using System.Collections.Generic;
using System.Threading;
public class StreamingChannel
{
    private readonly List<string> backgroundLinesList;
    private readonly object listLock = new object();
    private Thread streamReaderThread;

    public StreamingChannel()
    {
        streamReaderThread = new Thread(this.ReadWebStream);
        streamReaderThread.Start();
    }

    public List<string> Read()
    {
        if (!streamReaderThread.IsAlive)
        {
            streamReaderThread = new Thread(this.ReadWebStream);
            streamReaderThread.Start();
        }

        List<string> lines = null;
        lock (listLock)
        {
            if (backgroundLinesList != null)
            {
                lines = backgroundLinesList;
                backgroundLinesList = null;
            }
        }

        return lines;
    }

    private void ReadWebStream()
    {
        try
        {
            //stuff to set the stream
            HttpWebRequest webRequest;
            HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
            StreamReader responseStream = new StreamReader(webResponse.GetResponseStream(), encode);
            while (!responseStream.EndOfStream)
            {
                var line = responseStream.ReadLine()
                lock (listLock)
                {
                    if (backgroundLinesList == null)
                    {
                        backgroundLinesList = new List<string>();
                    }
                    backgroundLinesList.Add(line);
                }
            }
            log.Debug("Stream closed");
        }
        catch (Exception e)
        {
            log.Debug("WebStream thread failure: " + e + " Stack: " + e.StackTrace);
        }
    }
}

【讨论】:

  • 这很奇怪,因为如果我更改从流中读取的频率(从 0.5 秒到 2 秒),服务器无论如何都会关闭连接。此外,当我使用 2 秒间隔时,它读取的行数(大约 200 条)比 0.5 秒间隔的情况(大约 160 条)...这让我有点困惑......而且,不幸的是,Unity 不支持您的方法。
  • Unity script reference 表示 .NET 4.0 的 ConcurrentQueue 不受支持,因此我将其替换为锁定的 List。 Unity 不支持我的代码中的其他内容吗?
  • 根据Twitter,“Twitter 将关闭流连接...... [如果] 客户端读取数据太慢。每个流连接都由要发送到客户端的消息队列支持. 如果这个队列随着时间的推移变得太大,连接将被关闭。如果这是问题所在,服务器端队列将在不同时间填满,具体取决于服务器端推送率。
  • 实际上我发现 Unity 不是线程安全的 link。我试图做的是模拟你正在做的事情并经常从流中读取(每 0.1 秒),但发生的情况是流比以前更快地阻塞。这就是为什么我继续认为这就像我只能读取一定数量的数据然后我需要恢复通道......这可能吗?我怎样才能避免这种情况??
  • 在该链接中,重点是 Unity API 不是线程安全的,但您可以启动 .NET 线程以进行后台工作。这正是这段代码正在做的事情。后台线程从不调用任何 Unity API 函数。另一方面,Twitter 列出了关闭流连接的其他原因。今天晚些时候我会再读一遍。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-02
  • 1970-01-01
  • 2017-07-25
  • 2012-09-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多