我正在我的网站上开发用户之间的在线聊天。聊天是正常工作,但没有人可以进入网站,如果长投票连接是开放的。
我的代码[更新]:
$time = $_GET['time'];
while (true) {
$sth = $db->prepare("SELECT * FROM messages LEFT JOIN users ON users.username=messages.chat_msg_user_id WHERE chat_msg_client_id=:chat_msg_client_id AND chat_msg_id>:chat_msg_id AND chat_notification='0' ORDER BY chat_msg_time DESC LIMIT 1");
$sth->execute([":chat_msg_client_id" => $client_id, ":chat_msg_id" => $last_message_id]);
$messages = [];
while ($answer = $sth->fetch()) {
$msg = ["chat_msg_id" => $answer["chat_msg_id"], "chat_msg_user_id" => $answer["chat_msg_user_id"], "chat_username" => $answer['username'], "chat_user_photo" => $answer['mainphoto'], "chat_user_status" => $answer['status'], "chat_user_name" => $answer["name"], "chat_msg_from" => $answer['chat_msg_from'], "chat_msg_time" => date("H:i", $answer["chat_msg_time"]), "chat_msg_date" => date("m.d.y", $answer["chat_msg_time"]), "chat_msg_text" => mb_str_replace("\n", "<br>", $answer["chat_msg_text"]), "read" => $answer['chat_read'], ];
$messages[] = $msg;
$last_message_id = $answer["chat_msg_id"];
// some variables here for json_encode below //
}
if (count($messages) > 0) {
$sth2 = $db->prepare("SELECT count(chat_read) as unread_messages_count FROM messages WHERE chat_msg_client_id='$client_id' AND chat_read='0'");
$sth2->execute();
$answers = $sth2->fetch();
$unread_messages_count = $answers['unread_messages_count'];
echo json_encode(["command" => "new_messages", "messages" => $messages, "last_message_id" => $last_message_id, "chat_msg_id" => $chat_msg_id, "chat_user_name" => $chat_user_name, "chat_user_status" => $chat_user_status, "chat_user_photo" => $chat_user_photo, "chat_msg_from" => $chat_msg_from, "chat_msg_time" => $chat_msg_time, "chat_msg_date" => $chat_msg_date, "chat_msg_text" => $chat_msg_text, "unread_messages_count" => $unread_messages_count, ]);
exit();
}
usleep(10000);
if ((time() - $time) > 60) {
echo json_encode(["command" => "timeout"]);
exit();
}
}
更新2:我的主机提供商发送了一些关于它的信息,但我不明白它是什么…:
sendto(3, "\306\0\0\0\3SELECT * FROM messages LEFT JOIN users ON users.username=messages.chat_msg_user_id WHERE chat_msg_client_id='222' AND chat_msg_id>'571' AND chat_notification='0' ORDER BY chat_msg_time DESC LIMIT 1", 202, MSG_DONTWAIT, NULL, 0) = 202
更新3:我忘了说-我有两个长轮询连接每个用户。一个用于获取新聊天和新消息(用于通知),另一个用于在聊天时获取消息。
1条答案
按热度按时间vshtjzan1#
php通常使用线程池来处理请求。这种方法并不真正支持休眠执行。你很快就会耗尽可用的线程,新的请求不会得到处理,因为所有的线程都在休眠。
您要么需要增加线程的数量(这不会扩展,也可能不受宿主提供商的支持),要么切换到其他方法(通过使用支持异步请求处理的语言/框架,例如nodejs)。
另请参阅以下摘自关于php中长轮询的答案:
注意:对于一个真实的站点,在像apache这样的常规web服务器上运行它将很快占用所有的“工作线程”,并使其无法响应其他请求。。有很多方法可以解决这个问题,但是建议用python的twisted之类的语言编写一个“长轮询服务器”,它不依赖于每个请求一个线程。cometd是一个流行的框架(有多种语言版本),而tornado是一个专门为此类任务设计的新框架(它是为friendfeed的长轮询代码构建的)。。。但作为一个简单的例子,apache已经足够了!这个脚本可以很容易地用任何语言编写(我选择apache/php,因为它们非常常见,我碰巧在本地运行它们)
更新:
我的主机供应商说,apache有太多的连接到数据库和我的服务器死亡的原因
如果这是一个问题,那么在进入睡眠状态之前关闭数据库连接就可以解决这个问题(直到另一个关于php线程的问题出现为止),请参见下面的pdo。