For the technical principle of "server push" for HTTP long connections, you can check out this article from IBM. I simply made a DEMO.
The first is the homepage, which contains a text input and an iframe that displays chat content, as well as a hidden iframe is used to submit the form:
The code is as follows:
<?php //chat.php header('cache-control: private'); header('Content-Type: text/html; charset=utf-8'); ?> <html> <script type="text/javascript"> function submitChat(obj) { obj.submit(); document.getElementsByName('content')[0].value = ''; } </script> <iframe src="./chat_content.php" height="300" width="100%"></iframe> <iframe name="say" height="0" width="0"></iframe> <form method="POST" target="say" action="./say.php" onsubmit="submitChat(this)"> <input type="text" size="30" name="content" /> <input type="button" value="say" onclick="submitChat(this.form)" /> </form> </html>
The other one is to save the chat content submitted by the user. I simply write the text without any locking. This is just a simple version:
The code is as follows:
<?php $content = trim($_POST['content']); if ($content) { $fp = fopen('./chat.txt', 'a'); fwrite($fp, $content . "\n"); fclose($fp); clearstatcache(); } ?>
Next, let’s look at the main HTTP long connection part, which is the chat_content.php file:
The code is as follows:
<?php header('cache-control: private'); header('Content-Type: text/html; charset=utf-8'); //测试设置30秒超时,一般会设置比较长时间。 set_time_limit(30); //这一行是为了搞定IE这个BT echo str_repeat(' ', 256); ob_flush(); flush(); $fp = new SplFileObject('./chat.txt', 'r+'); $line = 0; $totalLine = 0; while (!$fp->eof()) { $fp->current(); $totalLine++; $fp->next(); } $fp->seek($totalLine); $i = $totalLine - 1; while (true) { if (!$fp->eof()) { if ($content = trim($fp->current())) { echo '<div>'; echo htmlspecialchars($content); echo "</div>"; flush(); $fp->next(); $i++; } } else { $fp->seek($i - 1); $fp->next(); } { //这里可以添加心跳检测后退出循环 } usleep(1000); } ?>
I will explain it line by line, which is actually easier to understand:
06. Set a timeout, because it requires Maintaining a long HTTP connection will definitely take a longer time, maybe a few hours. The article mentioned above also explains that only two of these long HTTP connections can be opened due to browser limitations. In addition, even if you set a never timeout, the configuration file of the server part (such as Apache) may also set the maximum waiting time for HTTP requests, so the effect may not be what you think. Generally, the default may be 15 minutes timeout. If you are interested, you can try to modify it yourself.
09. A section of blank space is output here, mainly because the manual has explained that the IE browser will not directly output the first 256 characters, so we first output some blank space casually to allow the subsequent content to be output, maybe Other browsers also have settings for other browsers. For details, you can check the description of the frush function in the PHP manual. The next 11 and 12 lines are to force these whitespace characters to be output by the browser.
13. ~ 20. The main purpose here is to calculate the number of file lines so that the content can be read from the end of this line.
The following while loop is an infinite loop, which outputs the file content in a loop. Each time it determines whether the end of the file has been reached. If a user writes to the file, the current detection is definitely not the end of the file, so the line is read and output. , otherwise move the pointer forward one line and continue to loop, waiting 1000 microseconds each time,
39. If a long connection is maintained, even if the client is disconnected, the server may not know that the client has been disconnected, so You may also need to do some heartbeat recording here. For example, each user keeps a heartbeat flag and updates the last heartbeat time every few seconds. When the last time is detected and has not been updated for a long time, the endless loop is launched and the HTTP connection is closed.