Reputation: 423
I'm writing a real time chat application using websocket with. I have a function that checks the database for new messages for a specific user. What I'm still missing is a way to infinitely call this method, so that the user can receive messages in real time.
Is there a way to run a background loop or something similar that can do the trick?
Thank you
Upvotes: 1
Views: 688
Reputation: 1269
The worst thing that you could do is set all of your sockets to non-blocking. This will create an idle loop, where your WS server will constantly check everything, will eat through your CPU time, accomplish nothing meaningful, and make people mad at you.
The next worst thing is to block indefinitely. This will require clients to periodically send data, chewing through bandwidth, accomplish nothing meaningful, possibly put your server in a hung state while there are no clients connected, and make people mad at you.
Instead, use blocking, but set a timeout. This is a balancing act that depends on your system, and only you can decide the duration of the timeout, hopefully with a bit of data to back up your decision.
The best place to put a timeout is socket_select()
. The code below will wait for a maximum of 1 second for new packets to come in, and when it gets bored, it'll do your DB stuff.
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!
}
}
Note that the timeout does not guarantee that tick()
will be called every second, or only once per second. If a packet comes in immediately, and is handled trivially, it could potentially only be a few milliseconds between calls to tick()
. On the other hand, if several packets come in and it's not trivial to handle each one, then it could be several seconds before tick()
gets called again.
Upvotes: 3
Reputation: 23389
My preferred method is a simple setTimeout()
call to repeatedly check the server for new messages.
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);
As mentioned in the comments, depending on the architecture of your application, it may or may not be a security concern to have the user's ID visible in the source code. If so, another option would be to generate a disposable unique identifier for your user. I personally wouldn't, but like I said, it depends on the architecture you've set up.
Anyway, in theory, you could generate a GUID from the server side script and pass it to your AJAX, then have ajax use the GUID in it's next call. The GUID would change with every call that way an unauthenticaed person won't be able to simply duplicate that ajax request.
A simpler method might be to just get the user_id from the session server-side instead of passing it as a parameter.
Upvotes: 2
Reputation: 1271
I have never built anything like this myself. But how about writing a regular script that polls the database and then pushes the messages (I guess ideally these should be seperate components) and setting up a scheduled tasks that runs this script in the frequency you desire.
Architecturally, this is probably not the most elegant solution, as you will also find people arguing arguing around a similar question and related proposition here: Invoking a PHP script from a MySQL trigger
But seeing how you asked your question and what that indicates about your setup, this might do for a start.
Upvotes: 0