php 从服务器向客户端发送数据?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16088691/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sending data from server to client?
提问by razz
I have a php server file and an HTML client file, the HTML file send ajax requests to the server to retrieve data every 500 ms
, this although works as expected it's causing high usage of memory and CPU on the client's device.
我有一个 php 服务器文件和一个 HTML 客户端文件,HTML 文件向服务器发送 ajax 请求以检索数据500 ms
,尽管这按预期工作,但它导致客户端设备上的内存和 CPU 使用率高。
PHP
PHP
if(isset($_POST['id']) && $_POST['id'] != '' )
{
$id = $_POST['id'];
$select = $con->prepare("SELECT * FROM data WHERE id=?");
$select->bind_param('s', $id);
$select->execute();
$result = $select->get_result();
while($row = $result->fetch_assoc())
{
echo $row['column 1'] . "\t" . $row['column 2'] . "\n";
}
}
AJAX
AJAX
function send(){
var formdata = new FormData(),
id = document.getElementById('id').value;
formdata.append('id', id);
var xhr = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
xhr.open('post', 'server.php', true);
xhr.send(formdata);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
console.log(xhr.responseText);
}
}
}
setInterval(function(){send()}, 500);
I would like to find an alternative solution to ajax, instead of sending numerous requests to the server and retrieving same data most of the time, it would be much more efficient if the server can interact with the client on data change or update.
我想找到 ajax 的替代解决方案,而不是向服务器发送大量请求并在大部分时间检索相同的数据,如果服务器可以在数据更改或更新时与客户端交互,效率会更高。
I can't use PHP Socket
or HttpRequest
medthods as they are not installed on my hosting server and i'm not sure if the later works. The only way i can think of is using SESSIONS
.
我不能使用 PHPSocket
或HttpRequest
medthods,因为它们没有安装在我的托管服务器上,我不确定后者是否有效。我能想到的唯一方法是使用SESSIONS
.
according to thisPHP server store all users sessions on the same directory on the server, therefore it may be possible to change sessions variables for a particular user directly on the file. the problem however is the data in those files are serialized and i'm not sure how to de-serialize the data and re-serialize them and then save the new data!
根据此PHP 服务器将所有用户会话存储在服务器上的同一目录中,因此可以直接在文件上更改特定用户的会话变量。然而问题是这些文件中的数据被序列化,我不确定如何反序列化数据并重新序列化它们,然后保存新数据!
Even if i was able to find a way to store updates on the session file, i still need to use setInterval to listen to the session's variable change every 500ms
although it's not ideal but it would be much better than using XMLHttpRequest
in terms of memory and CPU usage.
即使我能够找到一种在会话文件上存储更新的方法,我仍然需要使用 setInterval 来监听会话的变量变化,500ms
尽管它并不理想,但它会比XMLHttpRequest
在内存和 CPU 使用方面使用要好得多.
So what's the best way to do this? any help would be much appreciated.
那么最好的方法是什么?任何帮助将非常感激。
UPDATE:
更新:
I realized that SESSION
wont work because it can be read only by the server not the client, therefore i have to send ajax request to the server to get the variables which i was trying to avoid.
我意识到这SESSION
行不通,因为它只能由服务器读取,而不是客户端,因此我必须向服务器发送 ajax 请求以获取我试图避免的变量。
I tried long polling but i had many problems with it, flush
and ob_flush()
doesn't work on my server and i can't change the ini
settings. When trying the infinite loop i can't get it to break on data change:
我尝试了长轮询,但我遇到了很多问题,flush
并且ob_flush()
在我的服务器上不起作用,我无法更改ini
设置。尝试无限循环时,我无法让它在数据更改时中断:
if(isset($_GET['size']) && $_GET['size'] != '')
{
$size = (int)$_GET['size'];
$txt = "logs/logs.txt";
$newsize = (int)filesize($txt);
while(true) {
if($newsize !== $size) {
$data = array( "size" => filesize($txt), "content" => file_get_contents($txt));
echo json_encode($data);
break;
}
else{
$newsize = (int)filesize($txt);
usleep(400000);
}
}
}
it keeps going on and on, even if the logs.txt
size increase it wont break! how can i make it break and echo data on size increase?
它一直在继续,即使logs.txt
尺寸增加它也不会破裂!我怎样才能让它打破并回显大小增加的数据?
UPDATE 2:
更新 2:
it turned out the php cache the filesize when calling filesize()
method therefore the above loop will run indefinitely, the solution for that is to use clearstatcache()
method wich will clear the stored cache of the file size allowing the loop to break on filesize changes.
原来php在调用filesize()
方法时缓存文件大小,因此上述循环将无限期运行,解决方案是使用clearstatcache()
方法将清除文件大小的存储缓存,允许循环在文件大小更改时中断。
采纳答案by razz
Okay, after many tests and long research i came to the conclusion that PHP server can never interact with a specified client directly unless the client send a request to the server first.
好的,经过多次测试和长期研究,我得出的结论是,除非客户端先向服务器发送请求,否则 PHP 服务器永远不能直接与指定的客户端交互。
The only reliable solution i found is to use infinite loop which will only break on data change, this will reduce the frequency of ajax requests to the server considerably, hence increasing the performance and decreasing the usage of the Memory and CPU on the client's device, here how it goes:
我发现唯一可靠的解决方案是使用无限循环,它只会在数据更改时中断,这将大大降低对服务器的 ajax 请求频率,从而提高性能并减少客户端设备上内存和 CPU 的使用,这是怎么回事:
PHP 1 (Handles data update or new data insert to database):
PHP 1(处理数据更新或新数据插入数据库):
$process = $_POST['process'];
$log = "/logs/logs.txt";
if($process == 'update'){
//execute mysqli update command and update table.
$str = "Update on " . date('d/m/Y - H:i:s') . "\n";//add some text to the logs file (can be anything just to increase the logs.text size)
file_put_content($log, $str, FILE_APPEND);//FILE_APPEND add string to the end of the file instead or replacing it's content
}
else if($process == 'insert'){
//execute mysqli insert command and add new data to table.
$str = "Added new data on" . date('d/m/Y - H:i:s') . "\n";
file_put_content($log, $str, FILE_APPEND);
}
The above code will insert/update data, create file log.txt
if not existed and add additional text to it on each request. log.txt
will be used later in the infinite loop "below" and would break the loop when it's size change.
上面的代码将插入/更新数据,log.txt
如果不存在则创建文件,并在每个请求中添加额外的文本。log.txt
稍后将在“下面”的无限循环中使用,并在大小改变时中断循环。
PHP 2 (handles reading data requests):
PHP 2(处理读取数据请求):
if(isset($_POST['id']) && $_POST['id'] != '' && isset($_POST['size']) && $_POST['size'] != '')
{
$id = (string)$_POST['id'];
$init_size = (int)$_POST['count'];
$size = file_exists('logs/logs.txt') ? (int)filesize('logs/logs.txt') : 0;//$size is logs.txt size or 0 if logs.txt doesn't exist(not created yet).
$select = $con->prepare("SELECT * FROM data WHERE id=?");
$select->bind_param('s', $id);
while(true){ //while(true) will loop indefinitely because condition true is always met
if($init_size !== $size){
$select->execute();
$result = $select->get_result();
while($row = $result->fetch_assoc())
{
$data['rows'][] = array(
"column 1" => $row['column 1'],
"column 2" => $row['column 2'],
);
}
$data['size'] = $size;
echo json_encode($data);
break; //break the loop when condition ($init_size != $size) is met which indicates that database has been updated or new data has been added to it.
}
else{
clearstatcache(); //clears the chached filesize of log.txt
$size = file_exists('logs/logs.txt') ? (int)filesize('logs/logs.txt') : 0;
usleep(100000) //sleep for 100 ms
}
}
}
AJAX:
阿贾克斯:
var size = 0; //declares global variable size and set it's initial value to 0
function send(s){
var formdata = new FormData(),
id = document.getElementById('id').value;
formdata.append('id', id);
formdata.append('size', s);
var xhr = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
xhr.open('post', 'server.php', true);
xhr.timeout = 25000; //set timeout on xmlhttprequest to 25 sec, some servers has short execution tiemout, in my case it's 27 sec so i set the value to 25 sec.
xhr.send(formdata);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
var data = JSON.parse(xhr.responseText);
size = data.size;
console.log(data.rows);
setTimeout(function(){send(size)}, 100); //re-initiate the request after receiving data
}
}
xhr.ontimeout = function(){
xhr.abort(); //abort the timed out xmlhttp request
setTimeout(function(){send(size)}, 100);
}
send(size);
This is not the ideal solution but it reduced my xmlhttp requests from 2/sec to as low as 1/25 sec, hope that someone will be able to come up with a better solution.
这不是理想的解决方案,但它将我的 xmlhttp 请求从 2/秒减少到低至 1/25 秒,希望有人能够提出更好的解决方案。
回答by matthewmatician
Before we had capabilities to use sockets in browsers, we used Long polling. The basic idea is that instead of the browser making requests at regular intervals, the browser will make a request to the server, but the server won't respond until there is something worthwhile to share back to the browser. That means the request could be left open for 10ms or for hours.
在我们能够在浏览器中使用套接字之前,我们使用了长轮询。基本思想是浏览器不会定期向服务器发出请求,而不是浏览器定期发出请求,但服务器不会响应,直到有值得分享给浏览器的内容。这意味着请求可以保持打开状态 10 毫秒或数小时。
After the server responds with something, it is then the browser's job to make a new ajax request. This way, there is always a line open to the server.
在服务器响应某些内容后,浏览器的工作就是发出新的 ajax 请求。这样,总是有一条线路向服务器开放。
Refer to this questionfor more information.
有关更多信息,请参阅此问题。
回答by jimp
Answering the part of your question about directly editing a session...
回答有关直接编辑会话的部分问题...
To directly manipulate the session of a user, I will assume you know and can track any user's session ID (perhaps in your database on sign in).
为了直接操纵用户的会话,我假设您知道并且可以跟踪任何用户的会话 ID(可能在您登录时的数据库中)。
When you need to edit a user's session directly on the server:
当您需要直接在服务器上编辑用户的会话时:
- Retrieve user's last known session from the database.
- Call
session_close()
to close the current session (if there is one). - Call `session_name($sessionId)' with the session ID.
- Call
session_open()
to open that session.$_SESSION
should be populated with the session data. You will not need to unserialize anything. - Make your edits to the session.
- Call
session_close()
to reserialize the data.
- 从数据库中检索用户的最后一个已知会话。
- 调用
session_close()
以关闭当前会话(如果有)。 - 使用会话 ID 调用`session_name($sessionId)'。
- 调用
session_open()
以打开该会话。$_SESSION
应该填充会话数据。你不需要反序列化任何东西。 - 对会话进行编辑。
- 调用
session_close()
以重新序列化数据。
Alternatively, you coulddirectly open the session file, unserialize()
it, edit the data, and re-serialize()
manually.
或者,您可以直接打开会话文件unserialize()
,编辑数据,然后重新serialize()
手动。
回答by Simon
You could create an ajax request to an php script which will only return data if there is any new data. As long there is no new data the script keeps running in a loop until there is.
您可以创建一个对 php 脚本的 ajax 请求,如果有任何新数据,它只会返回数据。只要没有新数据,脚本就会一直循环运行直到有新数据。