NGINX - PHP-FPM服务电影寻求&连接手柄

时间:2014-12-09 15:18:34

标签: php nginx posix

我正在运行PHP-FPM 5.6和Nginx 1.7.6。

我正在使用PHP文件提供Matroska / Mp4电影。代码是:这一个:

<?php
register_shutdown_function( 'shutdown' );

$request = 'movie.mp4';

header( 'X-Accel-Buffering: no' ); //avoid nginx buffering.
header( 'Content-type: video/mp4' );

if ( file_exists( $request ) )
{

    $fp = @fopen( $request, 'rb' );

    $size = filesize( $request ); // File size
    $length = $size; // Content length
    $start = 0; // Start byte
    $end = $size - 1; // End byte
    header( "Accept-Ranges: 0-$length" );
    if ( isset( $_SERVER['HTTP_RANGE'] ) )
    {

        $c_start = $start;
        $c_end = $end;

        list( , $range ) = explode( '=', $_SERVER['HTTP_RANGE'], 2 );
        if ( strpos( $range, ',' ) !== false )
        {
            header( 'HTTP/1.1 416 Requested Range Not Satisfiable' );
            header( "Content-Range: bytes $start-$end/$size" );
            exit;
        }
        if ( $range == '-' )
        {
            $c_start = $size - substr( $range, 1 );
        }
        else
        {
            $range = explode( '-', $range );
            $c_start = $range[0];
            $c_end = ( isset( $range[1] ) && is_numeric( $range[1] ) ) ? $range[1] : $size;
        }
        $c_end = ( $c_end > $end ) ? $end : $c_end;
        if ( $c_start > $c_end || $c_start > $size - 1 || $c_end >= $size )
        {
            header( 'HTTP/1.1 416 Requested Range Not Satisfiable' );
            header( "Content-Range: bytes $start-$end/$size" );
            exit;
        }
        $start = $c_start;
        $end = $c_end;
        $length = $end - $start + 1;
        fseek( $fp, $start );
        header( 'HTTP/1.1 206 Partial Content' );
    }

    header( "Content-Range: bytes $start-$end/$size" );
    header( "Content-Length: " . $length );
    ob_end_flush();


    $buffer = 1024 * 8;
    while ( ! feof( $fp ) && ClientConnected() && ( $p = ftell( $fp ) ) <= $end )
    {
        $response = stream_get_line( $fp, $buffer );
        echo $response;

    }

    fclose( $fp );
}

function ClientConnected()
{
    if ( connection_status() != CONNECTION_NORMAL || connection_aborted() )
    {
        return false;
    }

    return true;
}


function shutdown()
{
    //main cause of problems is that line
    //posix_kill( getmypid(), 9 );
}

您会注意到上面的脚本支持Accept范围,因此用户可以查看电影该功能与电影本身完美配合。我可以通过访问该文件从我的播放器中看到电影而没有任何问题。

问题

问题在于关机功能。您可能会问我为什么要使用posix_kill并杀死php pid。

用户可以选择从我的应用程序中查看多部电影。用户对可以打开到我的服务器的连接具有LIMIT。这意味着如果用户有1个可用的插槽连接到服务器,他将只能同时打开一部电影。

出于这个原因,让我们说用户正在观看电影并且他想将当前电影ZAP(改变)到另一个电影。

他无法做到这一点,因为旧的连接不会快速结束,并且pid将保持打开几秒钟。

POSIX_KILL解释

如果我们取消注释上述代码的// posix_kill ,则用户根本无法看到任何电影,因为posix_kill函数会以某种方式覆盖以上所有标题和nginx / php都没有发送我在文件中的标题。

但是,如果我禁用HTTP SEEK并按照说明启用posix_kill,用户将能够观看电影,但他无法寻找。发生这种情况是因为当我们有Accept-Ranges标题时,玩家会在打开电影之前对电影做多个请求。

因此,例如,玩家将对该PHP文件执行2-3次请求以理解和识别搜索。然而,Posix_kill会快速杀死那些pid,并且玩家将无法选择正确的标题。

我们想要什么

因此,我们需要一种解决方案,当用户关闭连接但仍然是搜索支持时,将立即删除服务器中连接的PID。

PS。启用了posix_kill的上述代码可以在直播中完美地工作,因为我们没有寻求,所以玩家只会发出一个请求。

希望你了解我 谢谢

2 个答案:

答案 0 :(得分:1)

如果您没有任何安全问题。比使用nginx的mp4模块。它将你作为mp4的伪流媒体工作。在此之后,你不需要PHP在任何部分寻找电影。 Nginx handel本身。

答案 1 :(得分:0)

我用fastcgi_finish_request();

解决了这个问题

来自PHP手册:

  

此函数将所有响应数据刷新到客户端并完成   请求。这允许在没有执行的情况下执行耗时的任务   将连接保持打开状态。

我的关机功能变成了这样:

function shutdown()
{
    fastcgi_finish_request();
    posix_kill( getmypid(), 9 );
}