鍍金池/ 問(wèn)答/PHP  HTML/ ajax長(zhǎng)輪詢時(shí)php被阻塞

ajax長(zhǎng)輪詢時(shí)php被阻塞

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

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

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ù)請(qǐng)求
                }
            };
            $.ajax(setting);

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

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

    //建立長(zhǎng)連接,直到拉取到新消息后斷開(kāi)連接
    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;//斷開(kāi)連接
        }else 
            sleep(1);//掛起1s后繼續(xù)查詢
    }
    mysqli_close($conn);
}

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

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

回答
編輯回答
哎呦喂

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

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

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

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

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

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

對(duì)于session鎖已經(jīng)試過(guò)添加session_write_close();或session_commit();,沒(méi)有效果呢。

這段長(zhǎng)輪詢卡死給我一種php只能單線程處理的錯(cuò)覺(jué)?

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

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

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

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

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

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

2018年8月25日 23:01