在 Unity c# 中打开一个 StreamReader

Leave open a StreamReader in Unity c#

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

我有一个名为 StreamingChannel 的 class 创建流媒体频道

    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不支持

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

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

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