去过那里。做对并非易事。
我认为您必须做出一个重要决定:您是希望聊天真正即时进行,还是可以延迟 2 秒,直到每个人都看到新消息。
如果延迟没问题,您实际上可以每 2 秒轮询一次服务器以查看是否有新消息可用。没有人喜欢延迟,但取决于你想做什么,它可能不是那么糟糕。然后,服务器将检查每个请求的数据库/文件并返回更新。这是一个非常简单的解决方案,并且有效。 (如果您认为每 2 秒轮询一次会浪费资源并在服务器上造成不必要的负载……请继续阅读,替代方案可能会更糟。)
完全即时的聊天要求服务器可以立即向客户端发送新数据,而无需等待客户端请求。 HTTP 本身并不支持这一点,如果您不想使用任何 Flash/Java,我知道的唯一方法是使用彗星请求。这些请求(通常是 AJAX)会故意在服务器上挂起一段时间,然后在需要发送到客户端的新数据可用或发生超时时准确返回。每次彗星请求返回时,客户端都会处理数据并立即发出另一个彗星请求,该请求将再次挂起,直到有新数据可用。我相信每个纯 HTML/JS 的聊天网站都是这样做的(Omegle、Facebook 等)。
现在,这是最简单的部分。但是如何在服务器上实现呢?让我们看一下这种情况:您在聊天中有 10 个用户,这意味着 10 个客户端每个都有一个等待新数据的悬空彗星请求。其中一位用户在聊天中写入了一些内容,这会导致向服务器发出附加请求以发布文本。您如何使服务器上的 PHP 脚本的这一次执行导致其他 10 次执行停止等待并返回新数据? (您可以用 Perl 或任何东西代替 PHP。)您将需要允许多个脚本执行相互通信的东西。 (或者 PHP 代码本身可能每秒轮询一次数据库,但这又会引入延迟。)在这些脚本语言中,任何形式的进程间通信 (IPC) 都很困难,尤其是您不知道使用哪种模型时Web 服务器用于执行它们。例如,Apache 可以为每个请求创建一个进程,或为每个请求创建一个线程,或者两者兼而有之。但也许你的主机使用 IIS 或其他东西,所以在这种情况下很难进行 IPC。我最终做的是在 PHP 中创建一个自己的服务器组件,它一直在运行,它的任务是在 PHP 脚本的不同执行之间传递消息。是的,这需要 shell 访问。所有 PHP 执行都将通过套接字连接到该服务器组件,并且可以传递消息。做对很棘手,但最后效果很好。
不幸的是,comet 请求可能非常浪费内存和 CPU 周期。我的 Apache 服务器有一个基于 PHP 的进程执行模型。因此,当聊天中有 100 人时,这意味着随时有 100 个待处理的彗星请求,这意味着有 100 个 Apache 进程在运行。即使一个新的 Apache 进程只使用 10MB,也就是总共 1GB!那是很多内存,而这些过程只不过是在等待某些事情发生。聊天是一个令人难以置信的记忆猪。此外,这样的聊天确实会产生很多请求:每次有人在聊天中说些什么,所有 100 个请求都会返回,然后您将立即收到 100 个新请求。聊天中的用户数量增加两倍通常意味着请求数量增加四倍。你真的希望这很活泼。 Apache 在处理这个问题时并不总是那么有效。周围有一些 Web 服务器软件专门针对彗星请求进行了调整,并且可以很好地扩展,但这又需要比您拥有更多的服务器访问权限。
因此,为了完整起见,我的故事到此结束:与此同时,我放弃了所有 PHP 并完全重写了聊天内容。在我看来,Apache 和 PHP 非常不适合这种任务。现在有一个集成了高效的多线程 HTTP 服务器的 Java 服务器组件。我对它进行了压力测试,它的表现非常好:连接了 500 个垃圾邮件客户端,CPU 使用率不超过 15%,内存使用率保持在 150MB。这比我预期的要好得多。与 Apache/PHP 相比,它的响应能力也提高了很多。最终结果可以在http://www.dark-chat.info/查看,尽管由于各种原因聊天目前有些死。随着我有更多时间,这种情况有望改变。
好吧,我知道这对您没有多大帮助,因为您受到托管服务提供商的严格限制。如果没有 shell 访问权限,你能做的真的只有这么多。如果您可以延迟 2 秒(或延迟 1 秒)并且您不希望同时有超过 20 个用户,那么您真的可以进行轮询。有一些方法可以对此进行一些优化,例如,活跃用户可以获得 1 秒的投票,而那些很少写东西的用户可以获得 5 秒的投票。
也就是说,也许您也可以四处寻找某种托管解决方案。我确定您可以通过 iframe 嵌入聊天。
好的,这比我想要的要长得多。但我希望它可以帮助一些人。 :)