AS3上传速度测试

3
我正在使用 AS3 进行速度测试,并遇到了一个问题。在我的测试中,我使用 URLLoader( ),下载测试很好,但是上传测试却有些麻烦。我将一些二进制数据发送到我的 php 脚本,并检查 progress_event 来获取 bytesLoaded,计算当前速度,但是事件不会被触发,只有在整个文件发送完成后才会出现 complete_event。那么如何通过字节发送过程来确定速度呢?

P.S. 我不能使用 fileReference,因为我一个接一个地使用我的测试,不能让用户点击 filebrowse() 对话框。

谢谢。

        public function startme( ):void {

             _startTime = ( new Date( ) ).getTime( );

        var req:URLRequest = new URLRequest();
        req.url = "http://smart.t3a.ru/speedtest/test.php";
        req.contentType = 'application/octet-stream';
        req.method = URLRequestMethod.POST;
        req.data = Obj;

        //req.requestHeaders.push( new URLRequestHeader( 'Cache-Control', 'no-cache' ) );

        _loader = new URLLoader();
        _loader.dataFormat = URLLoaderDataFormat.BINARY;
        _loader.addEventListener(Event.COMPLETE,uploadComplete);
        _loader.addEventListener(ProgressEvent.PROGRESS, uploadProgress );
        _loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onstatus);
        _loader.addEventListener(IOErrorEvent.IO_ERROR, eIOError);
        _loader.load(req);


    }

    private function onstatus(event:HTTPStatusEvent):void
    {
        trace(event);
    }
    private function eIOError(event:IOErrorEvent):void
    {
        trace(event);
    }

    private function uploadComplete( e:Event ):void
    {
        var endTime:Number = ( new Date( ) ).getTime( );
        var totalTime:Number = ( endTime - _startTime ) / 1000;

        var totalKB:Number = Obj.length * 8 / 1024;
        //_speed = totalKB / totalTime;

        if (debug)
        {
            trace( "U total time: " + totalTime + " total KB: " + totalKB + " speed: " + speed + "KBps" );
        }

        dispatchEvent( e );
    }

    private function uploadProgress( e:ProgressEvent ):void
    {
        var endTime:Number = ( new Date( ) ).getTime( );
        var totalTime:Number = ( endTime - _startTime ) / 1000;
        if (totalTime > 1)
        {
            var totalKB:Number = e.bytesLoaded * 8 / 1024;
            _speed = totalKB / totalTime;

            if (debug)
            {
                trace( "u total time: " + totalTime + " total KB: " + totalKB + " speed: " + speed + "KBps" );
            }
            dispatchEvent( e );

        }
        if (totalTime > 7)
        {

            var ec:Event = new Event(Event.COMPLETE);
            _loader.dispatchEvent(ec);
            _loader.close();
        }
    }

更新: 我的php脚本:

    <?
    $postdata = file_get_contents("php://input");
    file_put_contents("inp.bin",var_export($postdata,true));
    echo "Done";
    ?>

是的,它很小,但我真的不需要数据,我需要检查上传速度有多快。

更新2

所以,在阅读了所有答案、评论并进行了数小时的谷歌搜索后,我可能已经找到了解决方案,但它的实现方式与我最初希望的不同。无论如何,非常感谢大家,我会很快发布解决方案。


你的代码在哪里?你应该使用 addEventListener 来设置事件监听器。 - vulkanino
_loader = new URLLoader(); _loader.dataFormat = URLLoaderDataFormat.BINARY; _loader.addEventListener(Event.COMPLETE,uploadComplete); _loader.addEventListener(ProgressEvent.PROGRESS, uploadProgress ); 一切都没问题,只是事件没有触发... - Den
你尝试过禁用你的反病毒软件吗?请参见http://stackoverflow.com/questions/2930513/monitoring-file-upload-progress-in-actionscript-3 - Creynders
反病毒软件没有问题。Event.COMPLETE 触发良好。 - Den
你看了我发的链接吗?因为 Event.COMPLETE 也触发得很好。只有进度事件没有触发。 - Creynders
是的,谢谢。但是,我最初使用的是 URLLoader,而不是 FileReference。在这里,Event.PROGRESS 只会在接收到数据时触发,而不是发送数据时触发。 - Den
6个回答

1

尝试添加这个,看看是否出现错误。那可能是问题所在。

_loader.addEventListener("ioError", ldrError);    

function ldrError(evt:*):void
{
    trace("ERROR");
}

可能是你的 PHP 脚本出了问题。


起初我使用 URLLoader 而不是 Loader 来处理二进制数据,但是 URLLoader 没有 contentLoaderInfo 属性。最后,我得到了 IOError 处理程序,但它没有跟踪任何内容。所以即使在完整数据上传后触发了 uploadComplete 事件,但进度仍未显示。我将在第一篇帖子中放置我的全部代码。 - Den

1

不要依赖于 ProgressEvent 的触发,尝试添加一个 ENTER_FRAME 监听器并从 _loader 实例中获取 bytesLoaded。如果 ENTER_FRAME 起作用,您可以尝试将其替换为重复的 TimerEvent,以减少 ENTER_FRAME 的处理负载。

我现在无法测试这个,但至少可以让您知道是 ProgressEvent 不触发还是流本身的问题。


谢谢。我已经创建了一个“TimerEvent”,但是有一个问题。“bytesLoaded”返回收到的字节数量,但我需要统计发送的字节数。 - Den
回顾过去,这显然是预期的行为。在这种情况下,我会说你需要超出Flash的范围。我不确定你的PHP脚本发生了什么,但如果上传确实是流式传输并且在上传过程中保存到服务器(例如使用FTP),那么在TimerEvent处理程序内,我会轮询第二个PHP脚本,该脚本调用**filesize()**函数来获取正在流式传输的文件大小,并将其返回给Flash。 - DNJohnson

0
你的ProgressEvents没有触发的原因是因为它们涉及到请求的下载部分(即来自服务器的响应),而不是上传部分。如果服务器响应很大(比如一个大型图像),你肯定会看到ProgressEvents,但由于你的脚本只返回了少量文本,在上传完成后非常快地完成,URLLoader在分派ProgressEvent之前就已经完成了。
正如你提到的那样,使用FileReference类是Flash能够检查正在进行的上传的唯一方法,但当然它也有许多限制。
我的建议是使用已知大小的POST负载设置你的URLLoader,然后在调用load方法之前存储new Date().getTime()。一旦COMPLETE事件返回,再次获取当前时间,并进行比较,以基于负载大小得出平均上传速率。请注意,这只是近似值,因为它不可避免地包含了下载部分,所以你计算出的速度将略低于实际速度。
另一个解决方法是在服务器端监视上传的运行进度和速度,并通过让Flash定期调用单独的上传进度脚本来报告这些信息,直到所有数据都被传输完毕。

0
也许我找到了,不要使用内置的下载模拟器,上传/下载真正的内容它会起作用!

不错的尝试 =) 但是仍然没有结果。我认为问题在于我的POST请求是“一次性”发送到服务器,而不是分块发送,因此只有Event.COMPLETE被触发。没有其他的了。我认为我需要使用类似流或其他速度计算方式的东西。 - Den
额,这是关于SOCKET_DATA的。你说的下载模拟器是用来干什么的? - Den

0

想知道您在下载方面测试的速度有多快,是否遇到了Windows系统的任何问题?我似乎在使用各种浏览器时都遇到了Windows系统中某种瓶颈,我的下载速度最高只能达到约25Mbps。而在Mac OS和Linux系统上,我可以达到大约100Mbps的线速度。


下载很好,获得实际速度,几乎等同于speedtest.net的结果。每秒计算接收字节数。这不是问题所在。 - Den

0
听起来像是服务器脚本出错了。这会快速返回一个响应,不会触发progressEvent事件。
在这种情况下,可能会返回类似于“在XX行的错误代码blah blah blah”的内容。
如果客户端得到响应,这种情况将触发complete事件。(200 OK)

你确认过服务器端的脚本没问题吗?

是的,没问题。而且“complete”事件触发得很好,但这不是我所需要的。 - Den
我仍然不确定你是否理解我的意思。你有跟踪服务器响应并验证数据是否正确吗?不要假设只因为你收到了完整的事件就没有服务器端问题。 - The_asMan
我们正在谈论“上传”部分。下载测试正常工作,进度在更新,字节数也在计算。但是“上传”部分不行。ProgressEvent 正在计算传入的字节数,但我需要传出的字节数。是的,在 completeEvent 中有一种获取上传速度的方法,如“delta Time/totalBytes”,但我需要在上传过程中动态地计算它。 - Den
再次强调,我仍然无法确定您是否已验证上传的服务器响应。您需要在上传完成时查看完整事件中的服务器响应。 - The_asMan
让我为您详细解释一下。服务器的上传脚本中有错误。 - The_asMan
在您的uploadComplete函数中,只需添加类似于trace(_loader.contentLoaderInfo.content)这样的内容,或者使用HTTPFox这个FireFox插件来检查从服务器发送的数据。 - The_asMan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接