php长轮询“;杀戮;服务器

php长轮询“;杀戮;服务器,php,mysql,Php,Mysql,我正在我的网站上开发用户之间的在线聊天。聊天功能正常,但如果长轮询连接打开,则没有人可以进入网站 我的代码[更新]: $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_

我正在我的网站上开发用户之间的在线聊天。聊天功能正常,但如果长轮询连接打开,则没有人可以进入网站

我的代码[更新]:

$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();
    }
 }

更新3:我忘了说-我每个用户有2个长轮询连接。一个用于获取新聊天和新消息(用于通知),另一个用于在聊天时获取消息

PHP通常使用线程池来处理请求。这种方法并不真正支持休眠执行。您很快就耗尽了可用线程,新请求将无法得到处理,因为所有线程都处于休眠状态

您要么需要增加线程数量(无法扩展,托管提供商可能不支持),要么切换到其他方法(通过使用支持异步请求处理的语言/框架,例如NodeJS)

另见以下摘录:

注意:对于一个真实的站点,在常规的web服务器(如Apache)上运行它将很快占用所有的“工作线程”,并使其无法响应其他请求。。有很多方法可以解决这个问题,但是建议用Python之类的语言编写一个“长轮询服务器”,它不依赖于每个请求一个线程。是一个流行的框架(有多种语言版本),是专门为此类任务设计的新框架(它是为FriendFeed的长轮询代码构建的)。。。但作为一个简单的例子,Apache已经足够了!这个脚本可以很容易地用任何语言编写(我选择Apache/PHP,因为它们非常常见,我碰巧在本地运行它们)


更新:

我的主机提供商说Apache和数据库的连接太多,我的服务器也因此死亡


如果这是一个问题,那么在进入睡眠状态之前关闭数据库连接就可以解决(直到另一个关于PHP线程的问题出现为止)。

我看不到代码中有任何地方设置了
$time
的值,所以它永远不会超时。@RecoveringNerdaholic我的代码中有上面的$time变量。@RecoveringNerdaholic当超时被触发时,我的js代码会发送一个新的长轮询连接,所以连接总是打开的(就像它应该打开的那样)。您在代码中的某个地方使用会话[session_start()]吗?@Lawrencerone谢谢您的回复。不,我没有使用会话。谢谢您的回复!我的主机提供商说Apache和数据库的连接太多,我的服务器也因此死亡。正如我在“更新2”中发布的那样。我有另一个网站有相同的在线聊天(但只有一个长轮询连接(仅用于获取消息)),聊天正常工作,服务器也正常工作。如果这是问题,它可能是可以解决的(目前),我相应地更新了答案。(在本例中,我对更新2的理解是错误的)因此在我的情况下$sth=null;($sth=$db->close();不工作)将关闭连接?我认为您需要将所有与连接相关的变量设置为
null
-至少
$db
$sth
。资源($db)是否表示连接在关闭时没有将变量设置为null。
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