【问题标题】:Detect TCP connection close when playing Flash video播放 Flash 视频时检测 TCP 连接关闭
【发布时间】:2011-02-15 23:21:55
【问题描述】:

在 Flash 客户端,我如何检测服务器何时故意关闭与其视频流的 TCP 连接?发生这种情况时,我需要采取措施 - 可能会尝试重新启动视频或显示错误消息。目前,连接关闭和连接速度慢在我看来是一样的。在这两种情况下,NetStream 对象都会引发 NetStream.Play.Stop 事件。当连接速度较慢时,通常会在几秒钟内自行恢复。我希望只在连接关闭时采取行动,而不是在连接缓慢时采取行动。

这是我的一般设置的样子。这是基本的NetConnection->NetStream->Video 设置。

this.vidConnection = new NetConnection();
this.vidConnection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, this.connectionAsyncError);
this.vidConnection.addEventListener(IOErrorEvent.IO_ERROR, this.connectionIoError);
this.vidConnection.addEventListener(NetStatusEvent.NET_STATUS, this.connectionNetStatus);
this.vidConnection.connect(null);
this.vidStream = new NetStream(this.vidConnection);
this.vidStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, this.streamAsyncError);
this.vidStream.addEventListener(IOErrorEvent.IO_ERROR, this.streamIoError);
this.vidStream.addEventListener(NetStatusEvent.NET_STATUS, this.streamNetStatus);
this.vid.attachNetStream(this.vidStream);

当服务器关闭 TCP 或连接冻结时,不会触发任何错误事件。只有NetStream.Play.Stop 事件会触发。下面是从最初播放视频到 TCP 连接关闭的过程。

connection net status = NetConnection.Connect.Success
playStream(http://192.168.0.44/flv/4d29104a9aefa)
NetStream.Play.Start
NetStream.Buffer.Flush
NetStream.Buffer.Full
NetStream.Buffer.Empty
checkDimensions 0 0
onMetaData
NetStream.Buffer.Full
NetStream.Buffer.Flush
checkDimensions 960 544
NetStream.Buffer.Empty
NetStream.Buffer.Flush
NetStream.Play.Stop

当我在连接关闭和连接缓慢期间对各种属性进行转储时,我看不到可以帮助我区分关闭和缓慢的独特值。

NetConnection->connected = true
NetConnection->connectedProxyType = none
NetConnection->proxyType = none
NetConnection->uri = null
NetConnection->usingTLS = false
VidStream->bufferLength = 0
VidStream->bufferTime = 0.1
VidStream->bytesLoaded = 3204116
VidStream->bytesTotal = 3204116
VidStream->currentFPS = 0
VidStream->time = 63.797

【问题讨论】:

    标签: flash actionscript-3 video tcp


    【解决方案1】:

    除了“NetStream.Failed”之外,我不知道任何表明连接断开的事件,它仅适用于 Flash Media Server(我什至不知道是否或何时触发) .

    您必须找到基于“NetStream.Buffer.Empty”的解决方案:每当发生此事件时启动一个计时器,让它等待足够长的时间以确保连接不太可能恢复,然后启动一个新的试图。您可以在每个“NetStream.Buffer.Full”上重置计时器,或者在电影结束或手动暂停时重置计时器,这样除非真的需要,否则不会造成任何伤害。

    【讨论】:

    • 1) 为什么不等待NetStream.Play.Stop 而不是Netstream.Buffer.Empty?从我的跟踪中,我有时会看到缓冲区在视频因缓慢或断开的 TCP 连接而冻结之前多次为空。 2) 我要等多久才能确定 TCP 连接没有中断并且我知道它只是一个慢速连接? 5秒? 10秒?任何数字都不会让我 100% 确信连接已关闭。
    • 1) NetStream.Play.Stop 在播放停止时发生,这可能是您或用户主动决定的。 Buffer.Empty 在缓冲区为空时发生,这表明连接可能很慢或有问题。这对我来说似乎更合乎逻辑。 2) 确实如此,但您列出的所有事件都不是连接断开所独有的。除非您找到另一个我不知道的,否则您必须做出权衡。顺便说一句,所有超时都可以,这是一种相当普遍的技术。这样,至少您可以决定用户可以等待多长时间。
    【解决方案2】:

    改用 NetConnection 状态:NetConnection.Connect.Closed

    我遇到了类似的问题并注意到 NetStream.bytesTotal 值在视频连接失败时被截断。因此,根据 NetStream 捕获视频长度(以字节为单位)并在调用 NetConnection.Connect.Closed 时使用它来检测失败。

    因为视频代码无法断章取义,所以我把它放在一起,建立在 Flash 的例子 @Flash NetConnection Example

    这是代码,cmets inline:

    public class NonTruncatedNetConnectionExample extends Sprite {
        private var videoURL:String = "http://www.helpexamples.com/flash/video/cuepoints.flv";
        private var connection:NetConnection;
        private var stream:NetStream;
        private var video:Video = new Video();
        // ADDITION: special length variable to check for truncation
        private var videoBytes:uint;
    
        public function NonTruncatedNetConnectionExample() {
            connection = new NetConnection();
            connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
            connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
            connection.connect(null);
        }
    
        private function netStatusHandler(event:NetStatusEvent):void {
            switch (event.info.code) {
                case "NetConnection.Connect.Success" :
                    connectStream();
                    break;
                case "NetStream.Play.StreamNotFound" :
                    trace("Stream not found: " + videoURL);
                    break;
                // ADDITION: this will be triggered when the connection is closed
                // on completion, or on failure
                case "NetConnection.Connect.Closed" :
                    if (this.videoBytes != this.stream.bytesTotal) {
                        // failure
                        // you can throw the error here
                        // or in the loadingProgress function below
                    } else {
                        // success
                        // the video loaded completely
                    }
                    break;
            }
        }
    
        private function securityErrorHandler(event:SecurityErrorEvent):void {
            trace("securityErrorHandler: " + event);
        }
    
        private function connectStream():void {
            var stream:NetStream = new NetStream(connection);
            stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
            stream.client = new CustomClient();
            video.attachNetStream(stream);
            stream.play(videoURL);
            addChild(video);
            // ADDITION: the loadingProgress function
            this.addEventListener(Event.ENTER_FRAME, loadingProgress);
        }
    
        /***
        ** ADDITION : loadingProgress captures the length of the video in bytes for use in comparison when
        ** NetConnection.Connect.Closed is called
        ** It also tracks current loading progress so you can use it as a buffer indicator
        */
        private function loadingProgress(E:Event):void {
            // check that this.stream.client has initialised & you have correct access to this.stream variables
            // bytesTotal is also a divisor so must be greater than 0 before continuing, or it will hard-fail
            if (this.stream.client && this.stream.bytesTotal > 0) {
                // sanity checker ;)
                trace("bytesLoaded = " + this.stream.bytesLoaded + " :: bytesTotal = " + this.stream.bytesTotal);
                // capture the video's total bytes only if the variable does not yet exist
                // before this point this.stream.bytesTotal returns a bogus (really big) number
                // watch out for capturing this.stream.totalBytes before this point, or you create a double negative,
                // because it won't match the actual bytesTotal & will therefore error [ it got me :( ; but then I got it ;) ]
                if (!this.videoBytes) this.videoBytes = this.stream.bytesTotal;
                // compare this to stream.totalBytes to detect truncation
                if (this.videoBytes != this.stream.bytesTotal) {
                    // error
                    // you can throw the error here if you want, or wait for the NetConnection.Connect.Closed switch above
                } else {
                    // or you can detach this event listener here while just holding on to the videoBytes variable
                    // & wait for the NetConnection.Connect.Closed switch above
                    // e.g. this.removeEventListener(Event.ENTER_FRAME, loadingProgress);
                }
                // use this to drive a buffer bar if you want
                var radian:Number = (this.stream.bytesLoaded / this.totalBytes);
                var percent:Number = radian * 100;
            }
        }
    
    }
    

    还有:

    class CustomClient {
        public function onMetaData(info:Object):void {
            trace("metadata: duration=" + info.duration + " width=" + info.width + " height=" + info.height + " framerate=" + info.framerate);
        }
        public function onCuePoint(info:Object):void {
            trace("cuepoint: time=" + info.time + " name=" + info.name + " type=" + info.type);
        }
    }
    

    【讨论】:

    • P.S.您必须在初始化时捕获 bytesTotal 变量,因为当 NetConnection 失败时它会被截断,因此 NetStream.bytesTotal == NetStream.bytesLoaded,因此在这种情况下比较是无用的,这就是最初让我感到困惑的原因......
    • 很高兴知道我们不是唯一遇到此问题的人。我们注意到这只发生在 Safari 中,而不是 IE、Firefox、Chrome。在其他浏览器中,当互联网连接恢复时,下载似乎会恢复。
    • 呵呵呵呵,我敢肯定,很多可怜的窥视者都对这个问题大发雷霆,我的特殊情况涉及在流式传输期间重新连接移动连接和热切换网络,这两者都会更改 IP 地址 - 很有趣不过,关于 Safari,我可能需要再次仔细检查代码......快乐!
    【解决方案3】:

    在 Windows 上使用 NetLimiter 进行密集测试(“意外”终止 TCP 连接)后,只有 NetStream.Buffer.Empty 会触发。

    weltraumpirat 为您提供的解决方案是您唯一可用的解决方案(启动计时器以查看您是否仍在积极接收数据)。

    显然 URLStream::connected 在丢失所有 TCP 连接后仍然为真,并暂停(没有任何 IO_ERROR 或其他事件/异常,就像 NetStream 一样)。 如果您的目标是 >10.1 Flash,您可以使用 URLStream 将数据加载到 NetStream::appendBytes 中(请参阅数据生成模式的文档(通过将 null 传递给 NetStream::play())),然后,当接收 NetStream.Buffer.Empty 立即检查 URLStream::connected 以查看您是否仍然连接到服务器,而不是启动 Timer。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-31
      • 2011-06-17
      • 1970-01-01
      • 2021-09-17
      • 1970-01-01
      • 2010-09-05
      • 1970-01-01
      • 2017-02-16
      相关资源
      最近更新 更多