2015-08-28 121 views
1

我在寫一個使用websocket的實時聊天應用程序。 我有一個函數,檢查數據庫中的特定用戶的新消息。 我仍然缺少的是一種無限地調用此方法的方法,以便用戶可以實時接收消息。PHP循環從數據庫中提取

是否有一種方式來運行一個後臺循環或類似的東西,可以做的伎倆?

謝謝

+0

搜索服務器發送的事件 – Ahmad

+0

你可以分享PHP以及數據庫細節? –

回答

3

,你可以做的最糟糕的事情是設置你所有的插座,以無阻塞。這將創建一個空閒循環,在那裏你的WS服務器將不斷檢查所有內容,會吃掉你的CPU時間,完成任何有意義的事情,並讓人們生氣。

接下來最糟糕的事情是無限期阻止。這將要求客戶定期發送數據,通過帶寬咀嚼,完成任何有意義的事情,可能會在沒有客戶端連接的情況下將服務器置於掛起狀態,並讓人們生氣。

而是使用阻塞,但設置超時。這是一個取決於你的系統的平衡行爲,只有你可以決定超時的持續時間,希望用一些數據來支持你的決定。

放置暫停的最佳位置是socket_select()。下面的代碼將等待最多1秒鐘的新數據包進入,當它變得無聊時,它會做你的數據庫的東西。

define("SOCKET_TIMEOUT", 1); 

function tick() { /* Put your DB checking here. */ } 

while (true) { 
    $read = get_array_of_sockets_that_may_have_sent_a_packet(); 
    $write = $except = null; // We probably don't care about these. 
    tick(); 
    $number_of_sockets_ready = socket_select($read, $write, $except, SOCKET_TIMEOUT); 
    if ($number_of_sockets_ready === false) { ... } /* Something went horribly wrong. socket_strerror(socket_last_error()) is your friend here. */ 
    elseif ($number_of_sockets > 0) { 
     // At least one socket is ready for socket_recv() or socket_read(). Do your magic here! 
    } 
} 

注意超時並不保證tick()將被稱爲每秒,或每秒一次。如果數據包立即進入,並且處理起來很平常,那麼在tick()的調用之間可能只有幾毫秒的時間。另一方面,如果有幾個數據包進來,處理每個數據包都不是微不足道的,那麼可能需要幾秒鐘才能再次調用tick()

+0

偉大的工作,但它一次只檢查一個用戶的新郵件。我無法找到解決方案來檢查連接的每個用戶的數據庫。 – michste93

+0

@ michste93'socket_select()'將套接字句柄的數組作爲參數,並通過引用修改該數組。當'socket_select()'返回時,您可以遍歷數組中剩餘的每個套接字句柄。 – Ghedipunk

+0

重新閱讀你的後續評論...你會在'tick()'期間檢查數據庫 - 沒有什麼神奇的,不需要'tick()'一次只處理一個連接/用戶。您可能希望擁有一個保存與站點用戶配對的活動WS連接的表,然後可以在連接和where子句中使用該表來將套接字句柄與具有等待通知的用戶ID相匹配。 – Ghedipunk

2

我的首選方法是一種簡單setTimeout()調用多次檢查新郵件服務器。

var checkForNewMessages = window.setTimeOut(function(){ 
    $.ajax({ 
     url: 'getChatUpdates.php', 
     type: 'POST', 
     data: {user_id: '<?php echo $_SESSION['user_id']; ?>' } 
    }).done(function(r){ 
     // do stuff to display new messages here 
    }); 
}, 5000); 

正如在評論中提到的,這取決於你的應用程序的架構,它可能是也可能不是一個安全問題有用戶的ID在源代碼中可見。如果是這樣,另一種選擇是爲您的用戶生成一次性唯一標識符。我個人不會,但正如我所說,這取決於您設置的架構。

不管怎樣,在理論上,你可以生成從服務器端腳本一個GUID,並把它傳遞給你的AJAX,然後對Ajax使用GUID在它的下一個電話。 GUID會隨着每次調用而改變,這樣一個未經授權的人將無法簡單地複製該Ajax請求。

一個更簡單的方法可能是拿到從會話服務器端,而不是USER_ID傳遞它作爲一個參數。

+0

好的方法,但你的例子是非常冒險的(用user_id)。也許提供你的答案一些安全建議或至少一個警告。 – sanderbee

+0

@sanderbee,我可以看到這是沒有必要的,但我不明白這可能是多麼的有風險。無論如何,更新了我的答案。 –

+1

它不是它在代碼中可見的部分,而是通過請求發送一個用戶ID。任何人都可以將此號碼從他自己的ID更改爲其他人的ID,因此也請閱讀他或她的所有消息。但無論如何,很好的編輯:) – sanderbee

0

我從來沒有建成這樣的事我自己。但是如何編寫一個輪詢數據庫的常規腳本,然後推送消息(理想情況下,這些應該是單獨的組件),並設置一個計劃任務,以您希望的頻率運行此腳本。

架構上來說,這可能不是最優雅的解決方案,這也是你會發現人們爭論圍繞着類似的問題,爭論及相關命題的位置:Invoking a PHP script from a MySQL trigger

但看到你如何問你的問題,有什麼指示有關設置,這可能會做一個開始。