我目前正在为网页游戏编写通信框架,通信地图如下所示:
代码如下:
test.PHP的:
<!DOCTYPE html> <html> <head> <title> Test </title> <script> function init() { var source = new EventSource("massrelay.PHP"); source.onmessage = function(event) { console.log("massrelay sent: " + event.data); var p = document.createElement("p"); var t = document.createTextNode(event.data); p.appendChild(t); document.getElementById("rec").appendChild(p); }; } function test() { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { console.log("reciver responded: " + xhr.responseText); } } xhr.open("GET","reciver.PHP?d=" + document.getElementById("inp").value,true); xhr.send(); console.log("you sent: " + document.getElementById("inp").value); } </script> </head> <body> <button onclick="init()">Start Test</button> <textarea id="inp"></textarea> <button onclick="test()">click me</button> <div id="rec"></div> </body> </html>
这需要用户输入(当前是用于测试的文本框)并将其发送到接收器,并写回接收器响应控制台的内容,我从未收到接收器的错误.它还为发送的SSE添加了一个事件监听器.
reciver.PHP:
<?PHP $data = $_REQUEST["d"]; (file_put_contents("data.txt",$data)) ? echo $data : echo "error writing"; ?>
您可以看到这非常简单,只有在发送回写成功之前才将数据写入data.txt. data.txt只是将“管”数据传递给massrelay.PHP.
massrelay.PHP:
<?PHP header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); while(1) { $data = file_get_contents("data.txt"); if ($data != "NULL") { echo "data: " . $data . "\n\n"; flush(); file_put_contents("data.txt","NULL"); } } ?>
massrelay.PHP检查data.txt中是否有任何数据,如果有,将使用SSE将其传递给任何有事件监听器的人,一旦读取数据,它将清除数据文件.
整个事情实际上是完美的,除了轻微的ishue可能需要30秒到10分钟,massrelay.PHP从数据文件发送数据.对于网络游戏,这是完全不可接受的,因为您需要实时操作.我想知道是否由于我的代码存在缺陷或者如果不是我正在思考硬件而花费这么长时间(我自己在戴着sempron的2006戴尔主持).如果有人发现任何问题,请让我知道谢谢.
如果您有兴趣自己看测试,可以找到它here
解决方法
我在您的代码中看到的三个问题:
>不要睡觉
>没有ob_flush
>会话
你的while()循环不断读取文件系统.你需要放慢速度.我在下面睡了半秒钟;尝试使用可接受延迟的最大值.
PHP有自己的输出缓冲区.您使用@ob_flush()来刷新它们(@抑制错误)和flush()来刷新Apache缓冲区.两者都是必需的,顺序也很重要.
最后,PHP会话锁定,因此如果您的客户端可能正在发送会话cookie,即使您的SSE脚本不使用会话数据,您也必须在进入无限循环之前关闭会话.
<?PHP header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); session_write_close(); while(1) { $data = file_get_contents("data.txt"); if ($data != "NULL") { echo "data: " . $data . "\n\n"; @ob_flush();flush(); file_put_contents("data.txt","NULL"); } usleep(500000); }
顺便说一下,关于使用内存数据库的另一个答案中的建议是好的,但文件系统开销是以毫秒为单位,因此它不能解释“30秒到10分钟”的延迟.