dpacmittal Posted March 10, 2009 Share Posted March 10, 2009 I know this question has been asked many times and it really doesn't have a nice answer. All people advice is to use timeout. And if people are inactive for some period of time then, log them off. But this doesn't solve my problem. Actually, I am trying to make a chat script in ajax for my website. My website will only be a chat site. I've got to a point where I can send the message, store it in database, then fetch the messages and display them in the browser. I've started to make a user's online list which will show people online in that chatroom. I've made another table for users online which will be used to store who's online in a particular room. When person clicks on logoff link, the row is deleted and he will not be shown on online user's list anymore. But the problem is, if he doesnt click on logoff, and directly closes the browser windows, the row in table doesn't gets deleted and he will be shown online forever. I can't use timeout because people can remain inactive in a chatroom for hours. What I was thinking is to make ajax send a message to web server every 30 seconds, by which web server would know who's online. If it doesn't receive that message from certain user, it means he has probably closed his browser. The problem is I don't know how to implement this idea. Also there will be a need of a script which would continuously check if the messages are received and delete the appropriate users for the table. My questions: 1) How to implement the idea above? 2) How do I make a script which would be continuously running on a server (do I have to put it in an endless loop. I just cant figure out how to make it run continuously)? 3) Is there any better idea for the job? 4) What method do publicly available chat scripts use for this purpose? I downloaded Blab! which is a well known chat script but couldn't understand how they implemented it? Any help would be greatly appreciated Quote Link to comment Share on other sites More sharing options...
rhodesa Posted March 10, 2009 Share Posted March 10, 2009 First, a question for you. What method do you use for getting new messages to the user? Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 10, 2009 Author Share Posted March 10, 2009 What method do you use for getting new messages to the user? I used POST method to transfer messages to the php file which then stores in a mysql table. Table also has line_id field which auto increments. When user logs in first, the latest line_id is fetched by using SQL MAX function. Ajax GET method is used to call another php file "retrieve.php" which shows latest messages from the given line number to latest line number. The messages are then appended using: document.getElementById("chatwin")=document.getElementById("chatwin")+httpReq.responseText; Quote Link to comment Share on other sites More sharing options...
rhodesa Posted March 10, 2009 Share Posted March 10, 2009 k, so assuming the AJAX call for retrieve.php happens every N seconds...if you put a line in the retrieve.php file that updates a field in your table, to record the last time they were active. then, when other clients get their retrieve.php, only return data where the last active was within N seconds (maybe N+2 seconds just to be safe) Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 11, 2009 Author Share Posted March 11, 2009 k, so assuming the AJAX call for retrieve.php happens every N seconds...if you put a line in the retrieve.php file that updates a field in your table, to record the last time they were active. then, when other clients get their retrieve.php, only return data where the last active was within N seconds (maybe N+2 seconds just to be safe) Thanks for your reply again. Is this what you are trying to say: I put a code in retrieve.php which would update the timestamp in database table everytime retrieve.php is accessed. When users list is shown, we will only display those user which accessed retrieve.php within last 3-4 seconds. I think this method would be very good. But I also want to delete the users, who have already closed their browser, from the table.. for which i need a script which runs continuously. Do you think it would be wise, if I put the deleting statement too in retrieve.php? Would it create mysql server unstable if I put deleting procedure in retrieve.php. There would be like 1000s of queries per second. Assuming there are 100 users online(There can be many more than that), retrieve.php is called every 2 seconds, retrieve.php would have a message retrieve query(SELECT), timestamp query(UPDATE) and deleting users query(DELETE FROM) and a message sending query(INSERT INTO). Quote Link to comment Share on other sites More sharing options...
rhodesa Posted March 11, 2009 Share Posted March 11, 2009 While the easiest thing to do is to put the DELETE in the retrieve.php file, it would probably be better to put it in a scheduled job that runs every 5 to 10 minutes or so to reduce the number of queries. Also, you may want to look into a couple other options to reduce the number of calls to retrieve.php. This would change everything we just discussed, but I think you would benefit in the long run. Long Poll - Instead of doing an AJAX call every 2 seconds (which is hard on the client and the server) you can do an AJAX call, and have the server keep it open until new data is ready for the client. Then, once the data is received by the client, it immediately does another AJAX call. Sometimes the request will come back immediately, sometimes it will stay open for several seconds. This should average out to less AJAX calls, but the applications should seem more responsive. Persistent Socket - There is a new application out there called Orbited http://www.orbited.org/ their webserver is not responding for me...I hope they still exist...but it's a server side application you install, and it does all the work for opening a persistent connection (like Gmail). I have not used it personally, but I hear good things. Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 12, 2009 Author Share Posted March 12, 2009 Thankyou for your reply, once again. As I am a newbie to AJAX, I didn't know about these techniques. I researched about them and I read about long polling and server pushing (Comet) techniques. I think long polling would be better for a chat system and I would like to try it. But the problem is I couldn't find any tutorials for getting started with it. I would be very grateful if you could post a short tutorial or point my to a website offering the same. Quote Link to comment Share on other sites More sharing options...
rhodesa Posted March 12, 2009 Share Posted March 12, 2009 Um, don't really have the time to write a full tutorial, but i'll try to cover the basics real quick. Client Side - Write a JS function that does an AJAX request to the server. The callback should handle the data returned from the server. After processing the data, immediately call the original function again to start another AJAX request. Server Side - The only change you should have to make server side, is putting all your code inside an infinite loop. Inside the loop, check for new data. If there is new data, print it and exit the script. As the last line inside the loop, put a usleep(500); and adjust the 500 to your desires. This will keep the infinite loop from eating up system resources. As another safety precaution, you may want to keep track of how long the loop has been running and return an empty data set after 20 seconds or so. This is to get around request timeouts. Hope that helps. Give a crack at writing the code, and let me know if you have any problems. Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 12, 2009 Author Share Posted March 12, 2009 Server Side - The only change you should have to make server side, is putting all your code inside an infinite loop. Thanks for your time and reply. I also thought the same thing about the infinite loop. Thanks a ton. I will try it and let you know what happens. Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 12, 2009 Author Share Posted March 12, 2009 I modified my retrieve.php to be: <?php session_start(); $id=$_SESSION['id']; include("connect.php"); $curr_time=time(); $updquery=mysql_query("Update users set lastactive='$curr_time' where user_id='$id'"); $delquery=mysql_query("delete from users where (lastactive+5)<'$curr_time'",$con); $lastmsg=$_SESSION['lastmsg']; for($i=0;$i<=20;$i++) { $q=mysql_query("Select Max(lineno) from abc"); $row2=mysql_fetch_row($q); if($row2[0]==$lastmsg) { usleep(1000000); } else { $res1=mysql_query("Select * from abc where lineno>'$lastmsg' and lineno<='$row2[0]' order by lineno ASC"); while($row = mysql_fetch_array($res1)) { echo $row['line']."<hr width=97% size=1 noshade>"; } $_SESSION['lastmsg']=$row2[0]; exit(); } } ?> Firefox loads the page in 10 seconds, the statusbar shows waiting for localhost. IE crashes on loading the page. And most importantly, the script doesn't work. Tell me if you want all the files. Help. Quote Link to comment Share on other sites More sharing options...
rhodesa Posted March 12, 2009 Share Posted March 12, 2009 try this: <?php session_start(); $id = $_SESSION['id']; include ("connect.php"); $curr_time = time(); $updquery = mysql_query("Update users set lastactive='$curr_time' where user_id='$id'"); $delquery = mysql_query("delete from users where (lastactive+5)<'$curr_time'", $con); $lastmsg = $_SESSION['lastmsg']; while(1){ //Infinite loop $q = mysql_query("Select Max(lineno) from abc"); $row2 = mysql_fetch_row($q); //Check for new message if ($row2[0] != $lastmsg) { $res1 = mysql_query("Select * from abc where lineno>'$lastmsg' and lineno<='$row2[0]' order by lineno ASC"); while ($row = mysql_fetch_array($res1)) { echo $row['line'] . "<hr width=97% size=1 noshade>"; } $_SESSION['lastmsg'] = $row2[0]; exit; } //Timeout after 20 seconds if(time() - $curr_time >= 20){ exit; } usleep(500); //Pause for a half second } ?> Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 13, 2009 Author Share Posted March 13, 2009 Hey rhodesa. Thanks for you reply. Had some problems with internet, thats why i am replying late. I got my script to work. I had problems due to usleep(1000000). PHP manual mentioned usleep(microseconds) as syntax. I thought 1second=1000000. Anyways, thanks a ton for teaching me long polling. It works like a charm and yes, my application seems more responsive. Just one another question. I want to make an admin section too. How do I get started with it? Quote Link to comment Share on other sites More sharing options...
rhodesa Posted March 13, 2009 Share Posted March 13, 2009 well...question is a little vague. there are lots of options (CMSs, etc) that already have a lot of the functionality of an admin built into them. but with such a custom app, you will probably need a custom admin. what kind of stuff are you looking for in the admin? Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 13, 2009 Author Share Posted March 13, 2009 I am building a chat script. I want to add these functions in admin panel: 1) A word list (it will be used to filter profane words from the messages users post) 2) Creating more rooms. 3) Max users allowed per room. 4) Monitoring chat and banning spammers. Quote Link to comment Share on other sites More sharing options...
rhodesa Posted March 13, 2009 Share Posted March 13, 2009 i would just create a folder called admin. inside that folder, lock it down with an htaccess/htpasswd setup: http://bignosebird.com/apache/a10.shtml then create a page (or a couple pages) in there to manage the stuff you just said. Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 13, 2009 Author Share Posted March 13, 2009 i would just create a folder called admin. inside that folder, lock it down with an htaccess/htpasswd setup: http://bignosebird.com/apache/a10.shtml then create a page (or a couple pages) in there to manage the stuff you just said. thankyou Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 14, 2009 Author Share Posted March 14, 2009 Hey, sorry to bother you again but the long polling isn't working. function retrieve() {var xhr = new httprequest(); var url = "retrieve.php"; xhr.open("GET",url,true); document.getElementById("transcript").innerHTML=document.getElementById("transcript").innerHTML+"<br>"+"sent"; xhr.onreadystatechange = function() { if(xhr.readyState==4 && xhr.status==200) {var prevtext=document.getElementById("chatwin").innerHTML; document.getElementById("chatwin").innerHTML=document.getElementById("chatwin").innerHTML+xhr.responseText; if(document.autoscr.scr.checked==true && document.getElementById("chatwin").innerHTML!=prevtext) { var objDiv = document.getElementById("chatwin"); objDiv.scrollTop = objDiv.scrollHeight; }} } xhr.send(null); } function startRetrieve() { setInterval("retrieve()",100); setInterval("user_fetch()",1000); } I've written document.getElementById("transcript").innerHTML=document.getElementById("transcript").innerHTML+"<br>"+"sent"; just to check at what interval the request is being sent. I notice that its being sent at just the interval I've mentioned ie. 0.1 second. It means that the long polling isn't working. How do I make another request as soon as the previous one is completed. I tried calling the function recursively but it crashes the browser(both firefox and ie). Help needed. Quote Link to comment Share on other sites More sharing options...
rhodesa Posted March 14, 2009 Share Posted March 14, 2009 You don't want to use any setTimeouts or setIntervals now. you are going to turn it into a recursive function. So, you run the AJAX once, and when the AJAX is done, it calls itself again. also, just to remind you...retrieve.php should only return new messages. function retrieve() { var xhr = new httprequest(); var url = "retrieve.php"; xhr.open("GET",url,true); document.getElementById("transcript").innerHTML += "<br>sending request"; xhr.onreadystatechange = function() { if(xhr.readyState==4 && xhr.status==200) { document.getElementById("transcript").innerHTML += "<br>data received"; var objDiv = document.getElementById("chatwin"); objDiv.innerHTML += xhr.responseText; objDiv.scrollTop = objDiv.scrollHeight; retrieve(); //Send it again } } xhr.send(null); } //This will start it when the page loads window.onload = function(){ document.getElementById("transcript").innerHTML += "<br>page is loaded"; retrieve(); } Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 15, 2009 Author Share Posted March 15, 2009 The above script works. Thanks. I was calling retrieve() outside the if condition. Now, I've got a new problem. When I send a message, it gets inserted into the database only after the execution of retrieve.php is complete. Meaning that, it isn't executing two php files simultaneously. What is the problem here? I checked that the function for sending message was being called but it got stuck on readystate=0. Only when execution of retrieve.php is complete, readystate changes and message gets sent. If you need whole code and sql dump file, let me know. This is giving me a lot of headache. Quote Link to comment Share on other sites More sharing options...
rhodesa Posted March 16, 2009 Share Posted March 16, 2009 are you sharing the same xhr object for sending messages and getting messages? you will run into a problem there. my suggestion is to just use a library like jQuery to handle all the ajax work for you Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 16, 2009 Author Share Posted March 16, 2009 are you sharing the same xhr object for sending messages and getting messages? you will run into a problem there. my suggestion is to just use a library like jQuery to handle all the ajax work for you no i am using separate objects for each request. Yeah.. will try my hand at jQuery. Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 16, 2009 Author Share Posted March 16, 2009 Hey I tried jQuery. Converted all my ajax request to use jQuery but I got same result. My query which retrieves new messages is holding up other ajax queries. I mean that, other queries wait for the completion of retrieving query before they themself get executed. Donno whats the problem. Help. Quote Link to comment Share on other sites More sharing options...
rhodesa Posted March 16, 2009 Share Posted March 16, 2009 hum...one shouldn't block the other. run this as a test, it should keep getting updates every 3 seconds even if you click the "Send Message" button: <?php if($_SERVER['REQUEST_METHOD'] == 'POST'){ if($_POST['action'] == 'message'){ print "Message received"; }elseif($_POST['action'] == 'update'){ sleep(3); print "Here are some updates"; } exit; } ?> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script> <script type="text/javascript"> function doUpdate ( ) { $('#output').append("Sending Request for updates<br />"); $.post('<?php echo $_SERVER['PHP_SELF']; ?>',{action:'update'},function(data){ $('#output').append("Update Received: " + data + "<br />"); doUpdate(); }); } function sendMessage ( ) { $('#output').append("Sending a message<br />"); $.post('<?php echo $_SERVER['PHP_SELF']; ?>',{action:'message'},function(data){ $('#output').append("Message sent: " + data + "<br />"); }); } $(function(){ doUpdate(); }); </script> <input type="button" value="Send Message" onclick="sendMessage();" /> <div id="output"></div> what OS/Browser are you testing in? Quote Link to comment Share on other sites More sharing options...
dpacmittal Posted March 16, 2009 Author Share Posted March 16, 2009 Your script is working fine. I have tested my script on Firefox 3, IE 7, Opera 9 and Google Chrome. I tried to debug it. I found that the function for sending message is being called but its readystate is not changing to 4. It only changes when the execution of retrieve.php has completed. The problem, I think, is not at the client side, but at the server side. I am using xampp. Do you think trying it on another server may help or maybe changing some php.ini settings? Quote Link to comment Share on other sites More sharing options...
rhodesa Posted March 16, 2009 Share Posted March 16, 2009 hum...if my test script worked on your xamp, then it's not the server. what is your current code for retrieve.php? where does the posted message go (aka does retrieve.php handle that too)? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.