4

几个访问者连接到http://site.com/chat.php

他们每个人都可以编写文本消息并将其发送到 chat.php,它会立即显示在每个人的浏览器上(http://site.com/chat.php

我必须使用数据库吗?我的意思是,AJAX 或 PHP 缓冲区功能是否足以满足此类会话聊天室的需求?

不同用户的会话如何相互共享数据?

任何想法或见解将不胜感激,谢谢!

编辑:感谢您的链接。但我想要的是将数据推送到客户端浏览器的方式。不断刷新客户端浏览器(AJAX 与否)是唯一的方法吗?此外,这里的挑战是不同的用户(例如 2、1 对 1)如何共享聊天文本?你如何储存它们?以及如何在 2 个客户端之间同步文本?最好不要使用数据库。

编辑 2:实际上Peter D 提到的YShout做得很好。它似乎并没有不断刷新浏览器。但我不明白它如何将新消息推送到现有用户的窗口。

4

5 回答 5

18

(大约)有 3 个用于创建聊天应用程序的选项:

插座

前端使用 flash/java 和套接字,后端使用支持套接字的编程语言。对于后端,我建议使用 java 或 python,因为它们具有多线程和 NIO 功能。使用 PHP 可以做到这一点(但 php 不能真正做到高效的多线程,而且通常不适合这个)。如果您需要高性能,这是一个选项,可能不是您想要的。

使用 ajax 并拉取

在这种情况下,所有客户端都会不断(例如每 2 秒)轮询是否发生了新情况。感觉很奇怪,因为您只会在这些时间间隔收到回复。此外,它会给您的服务器和带宽带来相当大的压力。您知道应用程序使用这种技术是因为浏览器会不断刷新。这是一个次优的解决方案。

使用 ajax 并推送

这适用于多部分响应,并且在后端有长时间运行的(php-)脚本。不是最好的解决方案,但在大多数情况下,它比拉动要好,而且它可以工作并用于几个知名的聊天应用程序。这种技术有时被称为COMET

我的建议:如果您需要用于生产用途的聊天应用程序,请安装现有的。编程聊天应用程序并不容易。

如果您只是想学习它,请从一个简单的 ajax/pull 应用程序开始,然后尝试使用 ajax 和 push 编写一个程序。

是的,很可能你需要一个数据库,我成功地实现了一个非常简单的 ajax/pull 解决方案,它可以与文本文件一起工作(但我肯定不会在生产中使用它!)。

(据我所知,但我很确定)没有服务器端后端(仅使用前端 javascript)就不可能创建聊天应用程序!

更新

如果您想知道数据推送是如何完成的,请查看此处的来源:http ://wehrlos.strain.at/httpreq/client.html 。异步多部分是你想要的:)

function asSendSyncMulti() {
    var httpReq = new XMLHttpRequest();

    showMessage( 'Sending Sync Multipart ' + (++this.reqCount)  );

    // Sync - wait until data arrives
    httpReq.multipart   = true;     
    httpReq.open( 'GET', 'server.php?multipart=true&c=' + (this.reqCount), false );
    httpReq.onload = showReq;
    httpReq.send( null );
}

function showReq( event ) {
    if ( event.target.readyState == 4 ) {
        showMessage( 'Data arrives: ' + event.target.responseText );
    }
    else {
        alert( 'an error occured: ' + event.target.readyState );
    }

}

每次数据到达时都会调用 showReq ,而不仅仅是像在常规 ajax 请求中那样调用一次(我在这里没有使用 jquery 或原型,所以代码有点肥胖 - 这真的很旧:))。

这是服务器端部分:

<?php

    $c = $_GET[ 'c' ];

    header('Content-type: multipart/x-mixed-replace;boundary="rn9012"');

    sleep( 1 );

    print "--rn9012\n";
    print "Content-type: application/xml\n\n";
    print "\n";
    print "Multipart: First Part of Request " . $c . "\n";
    print "--rn9012\n";
    flush();

    sleep( 3 );

    print "Content-type: application/xml\n\n";
    print "\n";
    print "Multipart: Second Part of Request " . $c . "\n";
    print "--rn9012--\n";

?>

更新2

关于数据库:如果你在后端有一个没有共享的架构,比如 mod_php/cgi,你肯定需要某种外部存储,比如数据库或文本文件。但是:您可以通过编写自己的 http 服务器来依赖内存(可以使用 php,但我不建议将其用于认真的工作)。这并不是很复杂,但可能有点超出你的问题的范围^^

更新3

我犯了一个错误!把一切都搞混了,因为我真的做了很长时间了。以下是更正:

  1. 多部分响应仅适用于 Mozilla 浏览器,因此用途有限。COMET 并不意味着多部分响应。

  2. COMET 意味着:传统的单部分响应,但在有可用数据之前保持(无限循环和睡眠)。因此浏览器对每个操作都有 1 个请求/响应(在最坏的情况下),而不是每 x 秒一个请求,即使没有任何值得响应的事情发生。

于 2009-04-21T13:47:15.290 回答
4

您提到希望它在没有数据库的情况下工作,并且没有客户端轮询服务器以获取更新。

理论上,您可以通过将聊天的“日志”存储在服务器上的文本文件中并更改您的页面以便用户在 chat.php 页面上执行 GET 请求来做到这一点,但 PHP 页面实际上从未完成发回给用户。(例如响应永远不会完成)

当没有消息时,您需要发回一些“无操作”数据以保持连接正常,但理论上这会起作用。

问题是,要完成上述工作还有很多工作要做。您需要将 AJAX 帖子发回服务器以提交新评论...用户的浏览器将一直在旋转(除非您将聊天日志嵌套在 iframe 中 - 例如更多工作)... 这种设置将很难管理。

我建议从其他地方获取一个免费的聊天脚本(例如http://tinychat.com/),或者如果你想自己动手(为了好玩/体验)然后继续,但从数据库开始并建立一个页面将从服务器推送和拉取消息。

最后,如果您担心用 AJAX 请求“锤击”服务器......不要。只需建立聊天,然后如果您发现存在性能问题,请返回 StackOverflow 并询问如何优化它,以便在没有活动时数百个请求不会淹没聊天。

于 2009-04-21T13:32:07.370 回答
2

虽然 HTTP 不是为轻松推送而设计的,但您可以通过让 PHP 脚本永不终止并仔细观察 JavaScript 结果来模拟推送连接。

本质上,您正在模拟流阅读器。

于 2009-04-21T13:49:19.467 回答
1

如果您希望新用户加载他们进入房间之前发生的聊天历史记录,则需要数据库或其他存储。除非你想创建一个学习聊天,否则有太多的免费使用来打扰。

http://tinychat.com是另一个简单的聊天网站。

AJAX 工作正常。我为我的一个网站创建了一个简单的页面。但我发现聊天并没有你想象的那么频繁。

通过托管 IRC 服务器并允许用户使用具有数据交换功能的 IRC 客户端,共享数据变得更加复杂并且更容易完成。尽管没有什么能阻止您让一个用户上传到网站,然后其他人下载。人与人之间使用网络界面会很困难,因为用户之间没有任何联系。

于 2009-04-21T13:10:59.637 回答
1

您可以使用PubNub 之类的服务完全使用 HTML 和 Javascript 来完成此操作。您不需要数据库,因为您可以使用历史 API之类的东西来填充最后 x 条聊天消息。

这是使用 PubNub 构建聊天应用程序的快速教程。

10 行代码中的实时聊天应用程序

在此处输入图像描述

Enter Chat and press enter
<div><input id=input placeholder=you-chat-here /></div>

Chat Output
<div id=box></div>

<script src=http://cdn.pubnub.com/pubnub.min.js></script>
<script>(function(){
var box = PUBNUB.$('box'), input = PUBNUB.$('input'), channel = 'chat';
PUBNUB.subscribe({
    channel  : channel,
    callback : function(text) { box.innerHTML = (''+text).replace( /[<>]/g, '' ) + '<br>' + box.innerHTML }
});
PUBNUB.bind( 'keyup', input, function(e) {
    (e.keyCode || e.charCode) === 13 && PUBNUB.publish({
        channel : channel, message : input.value, x : (input.value='')
    })
} )
})()</script>
于 2014-02-15T00:01:00.033 回答