使用PHP和AJAX进行长时间轮询...几乎就在那里

时间:2011-05-21 23:13:17

标签: php ajax json jquery long-polling

我正在与一个学校项目合作。该项目的基本思想是,我们有一些arduino盒子将一些传感器数据发送到mysql数据库,我们有一个显示它的网站。传感器数据发送可以说每6秒。

我没有很多PHP经验。但我正在修补我的方式,一步一步地学习......牛仔风格?的 =)

html / ajax / css:

    <!DOCTYPE html>
<html>
<head>
    <title>Arduino event poller</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript" charset="utf-8"></script>

    <style type = "text/css" media="screen">
        body{ font:13px/1.5 "helvetica neue", helvetica, arial, san-serif; background:#FFF; }
        #main{ width:430px; height: 300px; display:block; padding:10px 0; float: left; overflow: auto;}
        .event { display:block; background: #ececec; width:380px; padding:10px; margin:10px; overflow:hidden; text-align: left; }  
        .event img { display:block; float:left; margin-right:10px; }  
        .event p { font-weight: bold; }
        .event img + p { display:inline; }
        .patient-name { display:inline; color: #999999; font-size: 9px; line-height:inherit; padding-left: 5px; }
        .event-text{ color: #999999; font-size: 12px; padding-left: 5px; }
        .event-timestamp{ color: #000; padding-left: 5px; font-size: 9px;}
    </style>

    <script type="text/javascript" charset="utf-8">

        var timeStamp = null;

        /* Simple helper to add some divs.*/
        function addevents(patientroom, patientname, eventtyp, timestamp)
        {
            $("#main").append(
                "<div class='event'>"
                "<p>" + patientroom + "</p>"
                "<p class='patient-name'>" + patientname + "</p>"
                "<p class='event-text'>" + eventtyp + "</p>"
                "<p class='event-timestamp'>" + timestamp + "</p>"
                "</div>"
                );
        }

        /*This requests the url "getevents.php" When it complete*/
        function waitForEvents()
        {
            $.ajax({
                type: "GET",
                url: "getevents.php?timeStamp=" + timeStamp,

                async: true, /* If set to non-async, browser shows page as "Loading.."*/
                cache: false,
                timeout:50000, /* Timeout in ms */

                success: function(data, textStatus, jqXHR) /* called when request to getevents.php completes */
                {
                    addevents(data.patientroom, data.patientname, data.eventtyp, data.timestamp);
                        setTimeout(
                          waitForEvents, /* Request next event */
                          1000 /* ..after 1 seconds */                   
                        );
                    },
                error: function (XMLHttpRequest, textStatus, errorThrown){
                    alert("Error:" + textStatus + " (" + errorThrown + ")");
                    setTimeout(
                        'waitForEvents()', /* Try again after.. */
                        "5000"); /* milliseconds (5seconds) */      
                },
            });
        };

        $(document).ready(function(){
                waitForEvents(); /* Start the inital request */
        });
    </script>
</head>
<body>
    <div id="main">
    </div>
</body>
</html>

我的后端php:

<?php
function getEvents()
{
    $con = mysql_connect("localhost","***","***");
        if(!con)
        {
            die('Could not connect: ' . mysql_error());
        }
        mysql_select_db("arduino_db",$con);

    $result = mysql_query("SELECT * FROM events ORDER BY eventID DESC LIMIT 1");
    if($result)
    {
        $patientroom = $row['rumNr'];
        $patientname = $row['inneboendeNamn'];
        $eventtyp = $row['handelse'];
        $timestamp = $row['timestamp'];
    }

    if($row)
    {
        header('application/json');
                echo json_encode($row);
                exit;
    }

    $lastmodif = isset($_GET['timeStamp']) ? $_GET['timeStamp'] : 0;
    $currentmodif = filemtime($result);

    while($currentmodif <= $lastmodif)
    {
        unsleepp(1000);
        clearstatcache();
        $currentmodif = filemtime($result);
    }
}

?>

我的问题:

  1. 如何从db中获取每一行并将JSON格式的每一行返回到前端中的方法“waitForEvents”。
  2. 该示例不必是可扩展的,安全的或完整的,只需要工作 =)

    更新:基于Johns提示的新代码。我得到的只是一个空白页,没有错误。

2 个答案:

答案 0 :(得分:2)

对我来说,第一件事就是你的MySQL调用很糟糕。

当您运行此行时:

$result = mysql_query("SELECT * FROM events ORDER BY eventID DESC LIMIT 1");

您将获得MySQL资源。你需要利用它来获得你的行:

$result = mysql_query("SELECT * FROM events ORDER BY eventID DESC LIMIT 1");
if ($result)
{
   $row =  mysql_fetch_assoc($result);
   if ($row)
   {
        // Your result is here, as a big associative array.  Each column in your 
        // table is now keyed to this array.  Exact fields will depend on your DB.
        //
        // Just access it like something like this:

        $id = $row['id'];
        $time = $row['time_stamp'];

   }
}

以JSON回显它:

... // snip
   if ($row)
   {
        header('application/json');
        echo json_encode($row);
        exit;
   }
}
// handle your errors!

补充:OP问题中发现了其他错误:

//  The following line isn't valid.  This isn't what you'll get back from $.ajax.
//    success: function(patientroom, patientname, eventtyp, timestamp) 

//  Corrected code:
success: function(data, textStatus, jqXHR) 
/* called when request to getevents.php completes */
{
    addevents(data.patientroom, data.patientname, data.eventtyp, data.timestamp);
    setTimeout(
      waitForEvents, /* Request next event */
      1000 /* ..after 1 seconds */                   
    );
},

进一步更新。你混合了&amp;匹配上面的代码。

$result = mysql_query("SELECT * FROM events ORDER BY eventID DESC LIMIT 1");
if($result)
{
   // this has to go inside of this check.  This is where you *ASSIGN* $row.
   $row =  mysql_fetch_assoc($result);

   // You need to rekey $row before you output:
   $retVal = array('patientroom'=>$row['rumNr'],
                   'patientname'=>$row['inneboendeNamn'],
                   'eventtyp'=>$row['handelse'],
                   'timestamp'=>$row['timestamp']);

   // I'm not sure what you're doing with the incoming timestamp.  Should we just
   // return it back out?
   $retVal['ajax_timestamp'] = $_GET['timeStamp'];

   header('application/json');
   echo json_encode($retVal);
   exit; // this exits. Comment this out if you want, but don't try to write anything else out to the buffer.
}

// Not sure what you're trying to do here.  I'll comment out for now.
/*
$lastmodif = isset($_GET['timeStamp']) ? $_GET['timeStamp'] : 0;
$currentmodif = filemtime($result);

while($currentmodif <= $lastmodif)
{
    unsleepp(1000);
    clearstatcache();
    $currentmodif = filemtime($result);
}
*/

}

答案 1 :(得分:0)

我知道你不应该用php进行长轮询。如果你不是一个专业的php-hacker,还有很多其他原因,那就太乱了。

  • PHP用于快速执行(不等待)
  • PHP将强制您在服务器端进行某种轮询并依赖sleep()
  • PHP将占用您的RAM,同时为每个请求产生进程(Apache将这样做)

我的项目需要的是显示新数据而不刷新漏洞网站。我是这样做的:

<script type="text/javascript">
        var timeoutId;
        var intervalId;

        function doIt(){
            $("#main").load("refresh.php");
        }
        $(document).ready(function(){
            timeoutId = setTimeout(function(){
                doIt();
                intervalId = setInterval(function(){
                    doIt();
                }, 5000); //Request the doIt() method every 5ms.
            }, 3000); //Delay calculated on the server to trigger the function at the appropriate time
        }); 
    </script>