PHP不定式循环或jQuery setInterval?

goo*_*ing 5 php mysql jquery 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>
Run Code Online (Sandbox Code Playgroud)

PHP的:

public function chatting()
{
    while(true)
    {
       if(memcache_get(new_message))
          return new_message; 
       sleep(0.5);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

hak*_*kre 9

聊天是一对多的通信,而许多人中的每一个都可以发送消息并将从其他人接收消息.

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

  1. 输入
  2. 发信息
  3. 收到消息
  4. 出口

所以循环在客户端看起来像这样(伪代码):

while (userInChat)
{
    if (userEnteredMessages)
    {
        userSendMessages(userEnteredMessages)
    }
    if (chatNewMessages)
    {
        displayMessages(chatNewMessages)
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

        display(sendMessages)
    }
    function onReceive(messages)
    {
        display(messages)
    }
    function onExit()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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

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

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

非流关联消息是用户已经输入但尚未发送到服务器的消息.当服务器收到"免费"消息时,它可以通过分配ID将它们放入流中:

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

        display(sendMessages)
    }
Run Code Online (Sandbox Code Playgroud)

正如这个伪代码示例所示,这就是这里发生的事情.onUserInput事件获取的消息还不是流的一部分.sendMessages例程将返回其流式表示,然后显示.

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

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

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

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

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

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

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

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

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

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

仍然你的网络服务器和整体互联网连接可能不够快(虽然有保持活着).

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

让服务器变得简单也很好,因为每个客户端都依赖于它们,所以他们应该只做他们的工作就是这样.

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

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

希望这是有帮助的.


另外需要注意的是:HTML5 通过在线演示PHP/JS源提供了一些名为Stream Updates with Server-Sent Events的东西.HTML 5特征已经在javascript中提供了事件对象,其可以用于创建示例性聊天客户端传输实现.


Jam*_*son 5

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

我的建议是,如果它要么大a)你需要在你的web服务器层上疯狂缓存,这可能意味着你的AJAX调用需要有一个时间戳或b)使用像socket.io这样的东西,这是专为扩展实时Web应用而构建,并内置对频道的支持.


Bra*_*are 5

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

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


dev*_*Rew 5

它现在不是PHP或jQuery任务.Node.js的!有socket.io,表示WebSockets.

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

什么给你Node.js:

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

只需看看Node.js和Socket.io.这个解决方案对我有很大帮助.