PHP无限循环或jQuery setInterval?

时间:2011-12-26 16:04:19

标签: php jquery mysql memcached comet

JS:

<script>
function cometConnect(){
    $.ajax({
          cache:false,
          type:"post",
          data:'ts='+1,
          url: 'Controller/chatting',
          async: true,
          success: function (arr1) {
              $(".page-header").append(arr1);
          },
          complete:function(){
            cometConnect(true);
            nerr=false;
          },
          dataType: "text"
        }); 
}
cometConnect();
</script>

腓:

public function chatting()
{
    while(true)
    {
       if(memcache_get(new_message))
          return new_message; 
       sleep(0.5);
    }
}

这是一个比设置setInterval更好的解决方案吗?setInterval连接到PHP方法,如果每1秒钟就有一个返回消息(1秒增加+0.25每5秒让我们说)?

如果我使用第一个解决方案,我可能会使用sleep(0.5)它会立即给我消息,因为php循环很便宜,不是吗?

那么,什么解决方案更好(更重要的是,它需要更少的资源?)。因为这样会有数百个聊天记录。

另外,可以先解决问题吗?假设我会重新加载一个页面,否则我会每30秒停止一次执行,所以我不会得到502 Bad Gateway。

编辑:我相信第二个解决方案更好,所以我将重新实现我的网站,但我只是好奇这是否会给用户带来问题?可以预期会发生什么吗? 我注意到的第一个问题是,在至少有一条新消息之前你不能去其他页面。

5 个答案:

答案 0 :(得分:9)

聊天是一对多的通信,而众多人中的每一个都可以发送消息并接收来自其他人的消息。

这两个动作(发送,接收)不断发生。所以这看起来像一个无限循环,而用户可以进入(加入聊天)并退出(离开聊天)。

  1. 输入
  2. 发送消息
  3. 收到消息
  4. 出口
  5. 所以循环在客户端看起来像这样(伪代码):

    while (userInChat)
    {
        if (userEnteredMessages)
        {
            userSendMessages(userEnteredMessages)
        }
        if (chatNewMessages)
        {
            displayMessages(chatNewMessages)
        }
    }
    

    正如您在问题中已经注意到的,问题在于为网站实施这种聊天。

    实现这样一个&#34;循环&#34;对于一个网站,你首先要面对的情况是你不想在这里有一个实际的循环。只要用户在聊天,它就会运行并运行和运行。所以你想随着时间的推移分配循环的执行。

    为此,您可以将其转换为事件函数的集合:

    ChatClient
    {
        function onEnter()
        {
        }
        function onUserInput(messages)
        {
            sendMessages = send(messages)
    
            display(sendMessages)
        }
        function onReceive(messages)
        {
            display(messages)
        }
        function onExit()
        {
        }
    }
    

    现在可以触发事件而不是循环。左边是随着时间的推移触发这些事件的实现,但目前这并不是很有趣,因为它将取决于聊天数据交换的实际实现方式。

    总有一个远程点,聊天客户端(以某种方式)连接到它以发送自己的消息并从中接收新消息。

    这是某种聊天消息流。这看起来像一个循环,但实际上它是一个流。就像在聊天客户端循环中一样,它在某个时间点挂接到流上,并将从该流发送输入(写入)和接收输出(读取)。

    这在上面的ChatClient伪代码中已经可见,当用户输入一条或多条消息然后发送(写入)时会发生一个事件。并且onReceive事件函数中将提供读取消息。

    由于流是按顺序排列的数据,因此需要订购。由于这是基于事件的,并且有多个客户端可用,因此需要一些专门的处理。由于订单是相对的,它只能在它的上下文中工作。上下文可能是时间(一条消息在另一条消息之前出现),但如果聊天客户端有另一个时钟作为服务器或另一个客户端,我们就不能使用现有时钟作为消息顺序的时间源,因为它通常在WAN中的计算机之间有所不同。

    相反,您可以创建自己的时间来排列所有消息。通过跨所有客户端和服务器的共享时间,可以实现有序流。只需在中心位置编号即可轻松完成此操作。幸运的是,你的聊天有一个中心位置,即服务器。

    消息流以第一条消息开头,以最后一条消息结束。所以你只需要给第一个消息编号为1,然后每个新消息将获得下一个更高的数字。我们将其称为消息ID。

    因此,无论您使用哪种服务器技术,聊天都会知道消息的类型:带有ID的消息和没有ID的消息。这也表示消息的状态:不是流的一部分或部分。

    非流关联消息是用户已经输入但尚未发送到服务器的消息。当服务器收到&#34; free&#34;消息,它可以通过分配ID来将它们放入流中:

        function onUserInput(messages)
        {
            sendMessages = send(messages)
    
            display(sendMessages)
        }
    

    正如这个伪代码示例所示,这就是这里发生的事情。 onUserInput事件获取的消息尚未包含在流中。 sendMessages例程将返回其流式表示,然后显示。

    然后,显示例程能够以流顺序显示消息。

    所以无论如何实现客户端/服务器通信,使用这样的结构,您实际上可以粗略地处理基于消息的聊天系统并将其与底层技术分离。

    服务器唯一需要做的就是获取消息,为每条消息提供一个ID并返回这些ID。通常在服务器将消息存储到其数据库中时完成ID的分配。一个好的数据库需要正确地对消息进行编号,因此没有太多事情要做。

    其他交互是从服务器读取新消息。为了有效地通过网络执行此操作,客户端告诉服务器它从哪个消息中读取。然后,服务器将从那时起(ID)将消息传递给客户端。

    如图所示,来自&#34;无尽的&#34;在开始循环时,它现在变成了一个带有远程调用的基于事件的系统。由于远程调用很昂贵,因此最好能够通过一个连接传输大量数据。部分内容已经存在于伪代码中,因为它可以将一个或多个消息发送到服务器并立即从服务器接收零个或多个消息。

    理想的实现方式是与服务器建立一个连接,允许以全双工方式读取和写入消息。但是在javascript中还没有这样的技术。这些东西正在开发中使用Websockets和Webstream API等,但目前我们可以简单地看看我们拥有的东西:无状态HTTP请求,服务器上的一些PHP和MySQL数据库。

    消息流可以在数据库表中表示,该表具有用于ID的自动递增唯一键以及用于存储消息的其他字段。

    写事务脚本将只连接到数据库,插入消息并返回ID。这是一个非常常见的操作,它应该很快(mysql有一种memcache桥接,这应该使存储操作更加快速和方便)。

    读取事务脚本同样简单,它只会读取ID高于传递给它的所有消息并将其返回给客户端。

    保持这些脚本尽可能简单,并优化对商店的读/写时间,这样即使通过普通HTTP聊天,它们也可以快速执行并完成。

    您的网络服务器和整体互联网连接可能还不够快(尽管有keep-alive)。

    然而,HTTP应该足够好,暂时测试你的聊天系统是否实际上没有任何循环,而不是客户端,也没有服务器端。

    让服务器变得简单也很好,因为每个客户都依赖它们,因此他们应该只是做他们的工作而这就是它。

    您可以随时通过为聊天客户端提供发送和接收功能的不同实现来更改可与您的聊天客户端交互的服务器(或提供不同类型的服务器)。例如。我在你的问题中看到你正在使用彗星,这应该也可以,直接为彗星实施服务器可能很容易。

    如果以后的websockets更易于访问(出于安全考虑可能永远不会出现这种情况),您也可以为websockets提供另一种类型的服务器。只要流的数据结构完好无损,这将适用于彼此相邻的不同类型的服务器。数据库将照顾一致性。

    希望这有用。


    另外需要注意的是:HTML5提供了一个名为Stream Updates with Server-Sent Eventsonline demoPHP/JS sources的内容。 HTML 5功能已经在javascript中提供了一个事件对象,可用于创建示例性聊天客户端传输实现。

答案 1 :(得分:5)

我写了一篇关于如何处理类似问题的博客文章(使用node.js,但原则适用)。 http://j-query.blogspot.com/2011/11/strategies-for-scaling-real-time-web.html

我的建议是,如果它会变得很大a)你需要在你的web服务器层上疯狂缓存,这可能意味着你的AJAX调用需要有一个时间戳或b)使用像{{3 },用于扩展实时网络应用程序,并内置支持渠道。

答案 2 :(得分:5)

php中的无限循环可以并且将使用100%的CPU。睡眠功能将解决该问题。但是,您可能不希望为连接到服务器的每个客户端一直运行单独的HTTP进程,因为您将耗尽连接。你可以只有一个php进程查看所有入站消息,并在它们进入时将它们路由到正确的人。这个过程可以每分钟从一个cron作业启动一次。我多次写过这种类型的东西,它就像一个魅力。 注意:如果进程已经在运行,请确保不运行该进程,否则将遇到多处理问题(如获取双重消息)。换句话说,您需要使流程线程安全。

如果您想实时聊天,那么您可能需要查看StreamHub,它会打开与客户端浏览器的完全双工连接。

答案 3 :(得分:5)

现在不是PHP或jQuery任务。 Node.js的! 有socket.io,意思是WebSockets。

我将解释为什么node.js更好。我有一项任务是每次刷新页面标记,例如10秒。我用第一种方法完成了它。当持久用户数达到200时.http服务器和php出现问题。有很多请求是不必要的。

什么给你Node.js:

  • 为聊天创建单独的会议室(here
  • 仅为有更新的人发送数据(例如,如果我没有任何新消息,则当从数据库中进行选择时,我的刷新将被阻止)
  • 无论用户多少,
  • 每0.5秒向数据库运行一次查询

请看一下Node.js和Socket.io。这个解决方案对我有很大帮助。

答案 4 :(得分:2)

首先,问问自己是否有必要经常更新聊天。会发生什么类型的聊天?它是实时的吗?简单的Q&amp; A?技术支持?等等除了实时聊天案例外,最好使用基于JS的长轮询设计,因为瞬时响应并不重要。如果这是用于实时聊天,那么您应该考虑使用类似Gmail的设计,即保持XHR打开并在收到消息时将消息推送回客户端。如果需要考虑连接资源,可以使用长轮询进行非常短暂的间隔(例如5-10秒)。