鍍金池/ 問答/PHP  HTML/ ajax長輪詢時php被阻塞

ajax長輪詢時php被阻塞

剛接觸實時通訊這塊,知道用websocket更高效,但我想了解輪詢的實現(xiàn)過程,循序漸進

短輪詢用定時器setInterval已經(jīng)實現(xiàn)了,但長輪詢時后臺進入死循環(huán)模塊導(dǎo)致整個網(wǎng)站的php網(wǎng)頁無響應(yīng),比如刷新頁面、提交消息都沒法進行。具體代碼如下:

chat.php:

<div class="chat_content_input">
            <div>
                <textarea name="chat_input" class="chat_input"
                          style="width: 570px;height: 120px;margin: 5px;resize: none"></textarea>
            </div>
            <div style="text-align: right">
                <button class="chat_post">發(fā)送</button>
            </div>
</div>

chat.js:

//拉取新消息
            var setting = {
                type: "POST",
                dataType: "html",
                url: "./util/action.php?action=message_pull",
                data: {uid_get: $('#chat_content').attr('uid')},//傳遞目標(biāo)用戶uid
                success: function (msg) {
                    if (msg.length > 0) {
                        $('.chat_content_list_table').append(msg);//追加消息列表
                    }
                    $.ajax(setting);//立即繼續(xù)請求
                }
            };
            $.ajax(setting);

action.php中的對應(yīng)函數(shù):

function message_pull($conn)
{
    session_start();
    session_write_close();//關(guān)閉session鎖并沒有效果,仍被阻塞
    $uid_post = $_SESSION['userinfo'][0]['id'];//發(fā)送者,即當(dāng)前登錄用戶uid
    $uid_get = $_POST['uid_get'];//消息目標(biāo)用戶uid
    $message_list = '';

    //建立長連接,直到拉取到新消息后斷開連接
    while (true) {
        //查詢新消息
        foreach (select($conn, 'message', "(uid_get=$uid_post AND uid_post=$uid_get AND read_flag<>1)") as $message) {
            update($conn, 'message', 'read_flag=1', "id={$message['id']}");//每讀取一條則將其置為已讀狀態(tài)
            $message_list .= "<tr class='content_list_post' style='text-align: right;font-size: 18px'><td>" . $message['content'] . "</td></tr><tr><td style='text-align: right;font-size: 8px'>" . $message['post_time'] . "</td></tr>";
        }
        if (strlen($message_list) > 0) {
            echo $message_list;//輸出新消息
            break;//斷開連接
        }else 
            sleep(1);//掛起1s后繼續(xù)查詢
    }
    mysqli_close($conn);
}

之后測試一下,發(fā)現(xiàn)一旦php后臺進入while循環(huán),就會導(dǎo)致被阻塞,但我看到網(wǎng)上很多demo都這樣寫,于是感覺很疑惑,謝謝大大們指教

參考鏈接:https://www.cnblogs.com/zhenb...

回答
編輯回答
哎呦喂

post把數(shù)據(jù)庫存表,pull函數(shù)有數(shù)據(jù)了就中斷阻塞了,你一直沒有數(shù)據(jù)更新pull函數(shù)肯定就是阻塞的

2018年1月31日 00:15
編輯回答
尕筱澄

你看到的這樣例子的,應(yīng)該是區(qū)分serverworker吧。你的while適用worker進程;接口適合server。另外ajax的長輪詢的方式也不是你這樣操作。而是依靠前端的定時器,不間斷去請求后端。后端渲染數(shù)據(jù)而已。

2018年8月24日 18:09
編輯回答
空白格

你請求一次 action.php 就會創(chuàng)建一個php while 就會一直運行 死循環(huán) php當(dāng)然會死。 是ajax 來請求php 不是php循環(huán)去給前臺發(fā)送消息,你這while 完全沒意義。 當(dāng)你請求后臺 后臺才查詢數(shù)據(jù)或者更改狀態(tài),才正確。

2018年4月27日 12:15
編輯回答
傻丟丟

對于session鎖已經(jīng)試過添加session_write_close();或session_commit();,沒有效果呢。

這段長輪詢卡死給我一種php只能單線程處理的錯覺?

2018年5月6日 20:08
編輯回答
獨特范

應(yīng)該是php的session導(dǎo)致的,session是獨占的,所以在長輪訓(xùn)的時候,阻止了同一個client的其他請求,你可以在循環(huán)之前加上 session_write_close() 試試,應(yīng)該就不會阻塞了。

2017年10月16日 09:20
編輯回答
凝雅

我之前用長輪詢寫的即時聊天,你可以參考一下
http://blog.51cto.com/phpme/1...

2017年12月22日 15:04
編輯回答
澐染

雖然不懂php,但從字面上的意思,這當(dāng)然會死。。。長輪詢的意思是把timeout設(shè)高,而不是沒有timeout,如你代碼顯示,如果沒有新消息就一直是while(true)直接卡死了,應(yīng)該是沒有新消息并且定時器到時了就斷掉吧。

2018年8月25日 23:01