• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

[FRAGE] Clients refreshen

OK, danke für die Erklärung.
Habe jetzt nochmal komplett umgestellt, und verwende die Endlosschleife aus Posting 11. aber das bringt mich direkt wieder in neue schwierigkeiten. Ich komme einfach nicht weiter, und dreh bald durch :mad:
Zur Erläuterung erst nochmal um was es überhaupt geht. Denn vielleicht bin ich ja auf dem völlig falschen Dampfer:
Auf meiner Site gibt es eine dynamisch generierte Tabelle. Jeder User (ca 25) hat andere Werte drin in folgender Struktur:
Ich muss 1,50€ an Peter zahlen (Tabellenzeile: "Peter" ... "-1,50")
Peter kriegt 1,50@ von mir (bei ihm: "Ich"... "+1,50")
Die Daten werden jeweils in Localstorage gespeichert. Falls ein Handy kaputt geht/zurückgesetzt wird, sind die Daten futsch. Daher speichere ich nochmal auf dem Server in "Daten.json".
Das ganze funktioniert wunderbar. Aber nun habe ich folgende Pläne:

Wenn "A" einen neuen Wert einträgt, muss "B" diesen ja auch eintragen. Vergisst er dies, oder trägt was falsches ein, soll die Zelle rot werden. Stimmen beide überein--> grün.

Nun habe ich 2 Szenarien, bei beiden komme ich nicht weiter.


1.

Wenn ich die Daten in die "Daten.json" schreibe(Ajax-Post), schreibe ich zusätzlich die Änderung ("von wem", "für wen", "Wert").

In der Php überprüfe ich den Timestamp der Datei. Wenn der Timestamp < Alter Timestamp --> sende Daten(SSE). Dann ersetze alten Timestamp mit neuem Timestamp. Da die Schleife endlos läuft, müsste das ja funktionieren. Funktioniert aber nicht. Scheinbar ist alt und neu immer gleich.
PHP:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

$Altezeit=0;

while (1) 
{  

   $Dateizeit=filemtime(Daten.json);
   $string = file_get_contents("Daten.json");
   $json_a = json_decode($string, true);
   
   If ($Dateizeit<$Altezeit)
   {
	  echo "event: ping\n";
	  echo 'data: {"user": "' . $json_a['change']['user'] . '","Gegner":"' . $json_a['change']['Gegner'] . '","Wert":"' . $json_a['change']['Wert'] . '"}';
	  echo "\n\n";
	  ob_end_flush();
	  flush();
	  $Altezeit=$Dateizeit; 
   }
   
   sleep(1);
}
?>

2.

Ich sende dauernd die Änderungsdaten aus der "Daten.json". Unabhängig, ob geändert, oder nicht. Das wäre wohl am einfachsten.
Aber:
(Wir spielen ein Spiel) Alle 3-4 min geben 4 Personen Daten ein. Nun kann es ja passieren, dass 2 Leute (fast) gleichzeitig Daten eingeben. #1 lädt die Änderung hoch, #2 auch, bevor die 1Sek Loop gelaufen ist. Dann sind die Daten von #1 überschrieben, ohne verglichen worden zu sein.....

PHP:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');



while (1) 
{  
$string = file_get_contents("Daten.json");
$json_a = json_decode($string, true);

   echo "event: ping\n";
	  echo 'data: {"user": "' . $json_a['change']['user'] . '","Gegner":"' . $json_a['change']['Gegner'] . '","Wert":"' . $json_a['change']['Wert'] . '"}';

	  echo "\n\n";
	 ob_end_flush();
   flush();
   
  
   
   sleep(5);
}

3. Hab auch schon mal über eine Datei nachgedacht, in der die Änderungen "gestapelt" werden. Dann müsste die (SSE)PhP die abgearbeiteten Änderungen vom Stapel wieder löschen. Weiß aber nicht, wie ich das bewerkstelligen soll. Ich glaub das gibt immer mehr traffic/overhead.

Sorry, wenn ich euch so mit fragen bombardiere. Aber das ist
mein erstes HTML5
mein erstes JQuery
mein erstes JavaScript
mein erstes PHP.

Hab mich halt gleich an ein großes Projekt gewagt. Hier kann man sehen, wie das ganze funktioniert (ohne Datenvergleich)
 
In der Php überprüfe ich den Timestamp der Datei. Wenn der Timestamp < Alter Timestamp --> sende Daten(SSE). Dann ersetze alten Timestamp mit neuem Timestamp. Da die Schleife endlos läuft, müsste das ja funktionieren. Funktioniert aber nicht. Scheinbar ist alt und neu immer gleich.
nicht gleich, aber neu kann nur größer werden

Ich sende dauernd die Änderungsdaten aus der "Daten.json". Unabhängig, ob geändert, oder nicht. Das wäre wohl am einfachsten.
aber nicht schön

(Wir spielen ein Spiel) Alle 3-4 min geben 4 Personen Daten ein. Nun kann es ja passieren, dass 2 Leute (fast) gleichzeitig Daten eingeben. #1 lädt die Änderung hoch, #2 auch, bevor die 1Sek Loop gelaufen ist. Dann sind die Daten von #1 überschrieben, ohne verglichen worden zu sein.....
ich sehe kein problem, dann bekommt einer oder beide eben 2 änderungen, die von person 1 und die von person 2.

$json_a['change']
das mit dem change wird nicht funktionieren, da ja n personen die änderungen mitbekommen müssen. du findest nicht den zeitpunkt um das change zurückzusetzen. das geht nur über einen vergleich - jedenfalls mit der jetzigen mehfach redundanten datenhaltung - die suboptimal ist.
besser wäre es die daten nur einmalig auf dem server zu halten und neue einträge (die ja immer nur 2 leute betreffen) durch den 1. mit flag "nicht verifiziert" einzutragen und sie dem 2. zur verifikation zu geben. bestätigt er das ist alles gut und das flag wird auf "verifiziert" geändert, lehnt er ab, wird das flag auf "abgelehnt" geändert.
wenn du jedesmal einen zeitstempel (servertime) setzt, und bei jedem senden auch einen an den client sendest, könntest du alle hinzugekommenen einträge seit der letzten meldung an den client raussuchen und nur diese an den client senden.
einfacher ist es, immer alle zu senden (die den nutzer betreffen) - so oft dürfte sich ja nichts ändern hängt also von der menge ab, ob man nur änderungen oder immer alles senden kann.
 
nicht gleich, aber neu kann nur größer werden
Sollte natürlich If ($Dateizeit>$Altezeit) heißen. Hatte die Datei schon umgestrickt, und nur hier zur erklärung nochmal zusammengebastelt, ohne zu testen. Mit > funktioniert auch nicht. Am Client kommt nix an. Auch wenn ich die JSON-Datei neu beschreibe.

ich sehe kein problem, dann bekommt einer oder beide eben 2 änderungen, die von person 1 und die von person 2.
das mit dem change wird nicht funktionieren, da ja n personen die änderungen mitbekommen müssen.
Also ich speichere eigentlich immer nur eine Änderung. Wenn ich jede Änderung speichere, wird die Datei ja immer größer. Und es muss immer nur einer mitkriegen.

Wenn Peter bei Udo etwas einträgt, wird die JSON geladen, das Objekt Peter[Udo] geändert, und damit ich nicht die gaze Datei auf Änderung untersuchen muss, dies nochmal als Objekt in die Datei geschrieben: "change":{"user":"Peter","Gegner":"Udo","Wert":"1,50"}

Nun soll mittels der (SSE)-PHP das Objekt "Change" gesendet werden.

Bei einem eingehenden Ping-Event würde ich dann ungefähr so abfragen (Noch keine näheren Gedanken gemacht): If user== Udo .... if Peter==1,50 --> grün
Alle kriegen zwar die Änderung, aber nur Udo wird sie verarbeiten.

Mein eigentliches Problem ist immer noch: Wie kann ich ein SSE absenden wenn sich was geändert hat ("nur dann").

Vielleicht mach ich mir doch nochmal Gedanken um eine Stapeldatei. In der jede Änderung hinten angehängt wird. Quasi eine Liste mit Veränderungen.
Die SSE-PHP ruft die Datei ab, sendet eine Änderung, und löscht sie aus der datei. So ähnlich irgendwie.
Oder sendet alle Änderungen. Da weiß ich aber noch nicht, wie ich das beim Client verarbeiten kann.
 
Sollte natürlich If ($Dateizeit>$Altezeit) heißen. Hatte die Datei schon umgestrickt, und nur hier zur erklärung nochmal zusammengebastelt, ohne zu testen. Mit > funktioniert auch nicht. Am Client kommt nix an. Auch wenn ich die JSON-Datei neu beschreibe.
If oder if?

Also ich speichere eigentlich immer nur eine Änderung.
wie soll das gehen? dass 2 leute parallel ändern ist ja möglich.

Wenn ich jede Änderung speichere, wird die Datei ja immer größer.
ja, ist ja erst mal kein problem, selbst wenn du die gesammte historie speicherst, vielleicht ist dann json als datenformat nicht ideal, sondern eher eine datenbank. aber wenn du nur änderungen speicherst die noch nicht abgerufen wurden ist das kein problem.

Und es muss immer nur einer mitkriegen.
wenn udo einträge macht für peter und olaf sind es schon 2.
wenn dann gleichzeitig heiko noch für udo und peter was hinterlegt, sind wir bei 3.
wenn peter jetzt online kommt, sind für ihn 2 einträge vorhanden, von heiko und udo.
jetzt ist die sekunde von udo's sse-script vorbei und das php-script muss ihm den eintrag von heiko senden.
olaf hat erst mal keine lust mehr und loggt sich erst in 4 wochen wieder ein, solange muss der eintrag von udo für ihn gespeichert bleiben

Wenn Peter bei Udo etwas einträgt, wird die JSON geladen, das Objekt Peter[Udo] geändert, und damit ich nicht die gaze Datei auf Änderung untersuchen muss, dies nochmal als Objekt in die Datei geschrieben: "change":{"user":"Peter","Gegner":"Udo","Wert":"1,50"}
wenn du für jeden nutzer einen index vergibst und dann eine matrix [user][user] aufbaust und darin ein array von objekten der art {amount: 1.50, verified: 1, timestamp: <<servertime>> } speicherst kannst mit data[udo_idx] alle einträge finden die für udo sind.
dann kannst du data[udo_idx][peter_idx] alle einträge finden die für udo von peter sind, da du nicht weißt, wer alles einträge gemacht hat, musst du für udo alle einträge aller user abfragendata[udo_idx][0-n]. drin sind dann wieder n einträge, entweder schon aufsummiert oder auch nicht für bestätigte beträge, noch nicht bestätigte und abgelehnte. die sind jeweils mit zeitstempel, so dass du nur die senden müsstest, welche nach der letzten abfrage hinzugekommen sind.
 
if. Wie gesagt, Hab jetzt nur nochmal schnell zusammengeschrieben ohne zu testen, um hier zu posten.

wenn udo einträge macht für peter und olaf sind es schon 2.
Das wird nicht vorkommen. Wir spielen Doppelkopf. Es spielen 4 Leute, immer 2 gegen 2 (Außer bei Solo: 3 gegen 1).
Nach dem spiel -Udo und Olaf- gegen -Peter und Markus-. Udo sagt "ich schreib mit Markus". Dann schreibt Olaf mit Peter.
Udo klickt auf Markus, wählt einen Wert, und bestätigt. In dem Moment (Pagebeforeclose) wird die Änderung hochgesendet.
Bei Solo schreibt Udo nacheinander mit den 3 Leuten und jedesmal wird gesendet.

Für den unwahrscheinlichen Fall, dass alle 4 gleichzeitig absenden, gehe ich mal davon aus, dass ein schreiben in die Datei nicht möglich ist, solange sie für einen anderen Schreibvorgang offen ist. Dann wird erst nach abschluss des ersten Vorgangs, der nächste geschrieben. Oder liege ich da falsch?

die sind jeweils mit zeitstempel, so dass du nur die senden müsstest, welche nach der letzten abfrage hinzugekommen sind.

Jetzt hast du mich erstmal verwirrt. Probiere grade was anderes, und werde bei scheitern dann nochmal darauf zurückkommen.
Im Moment bin ich an folgendem:

Habe eine Datei "Change.json" mit fiktiven Änderungen aufgebaut:
Code:
{
"index":3,
"1":{"user":"Niemand","Gegner":"Niemand","Wert":"0,00","alterWert":"0,00"},
"2":{"user":"Niemand","Gegner":"Niemand","Wert":"0,00","alterWert":"0,00"},
"3":{"user":"Niemand","Gegner":"Niemand","Wert":"0,00","alterWert":"0,00"}
}

Hier werden Änderungen hinten drangehängt:
Code:
$(document).on( "pageshow", "#home",function(event) 
{
   var user="Fedi";
   var Gegner="Hubi";
   var Wert='1,00';
   var alterWert='3,00';
   
    $("#Sendbutton").click(function()
   {
	  $.getJSON('Daten.json', function(daten) /* JSON-Datei laden */
	  {	
	     
		 daten[user][Gegner]="15,80"; 	 /* JSON-Daten verändern*/
		
		 
		 $.ajax(         /*und geänderte Daten wieder hochladen*/
		 {
			type: "POST",
			url: 'update.php',
			data: {message :JSON.stringify(daten), file: 'Daten.json'}			
		 });				  
	  });
	  
	  
	  
	  $.getJSON('Change.json', function(data)   /* Change.json zum verändern runterladen*/
	  {	
		 data.index++;    /* im Data.index ist die Menge der Änderungen gespeichert. Wird um 1 erhöht*/
		 var x={};
		 x[data.index]={"user":user,"Gegner":Gegner,"Wert":Wert,"alterWert":alterWert};		 
		 data = $.extend(data,x);		 /* Ein neues Objekt hinten angehängt*/
		 
		 
		 $.ajax(         /*und wieder hochladen*/
		 {
			type: "POST",
			url: 'update.php',
			data: {message :JSON.stringify(data), file: 'Change.json'},  
			
		 });				  
	  });   
   });
});

Nun möchte ich in der "refresh.php" diese Datei einbinden, wenn Index > 0 jedes Objekt einzeln, oder auch gleichzeitig per SSE runterschicken, und in der change-Datei wieder löschen/Index zurücksetzen. Müsste doch so machbar sein...
 
Zuletzt bearbeitet von einem Moderator:
Den Code hab ich leider nicht mehr, da ich jetzt anders vorgehe.

Aber leider "flushed" mein SSE nicht. Kannst du erkennen, warum?

Zur erklärung des js-Codes:
Bei Button-Click wird die Change.json eingelesen (den vorherigen request der "Daten.json" kann man jetzt mal außer acht lassen).
Der Inhalt der Datei sieht etwa so aus:
{"1":{"user":"Niemand","Gegner":"Niemand","Wert":"0,00","alterWert":"0,00"},"2":{"user":"Niemand","Gegner":"Niemand","Wert":"0,00","alterWert":"0,00"},"3":{"user":"Niemand","Gegner":"Niemand","Wert":"0,00","alterWert":"0,00"},"index":3}

Der Index wird um 1 erhöht, und ein neues Objekt drangehängt. Also in dem Fall "4":{"user":"Niemand","Gegner":"Niemand","Wert":"0,00","alterWert":"0,00"}
Und wieder hochgeladen.

Die refresh.php liest die Datei, sendet den Inhalt per SSE, und löscht dann alles außer dem Index (Dann 0).

Die Dateivorgänge funktionieren, aber im Browser kommt nix an.

Code:
$(document).on( "pageshow", "#home",function(event) 
{
   var user="Fedi";
   var Gegner="Hubi";
   var Wert='1,00';
   var alterWert='3,00';
   
   var source = new EventSource("refresh.php");
   source.addEventListener("ping", function(e) 
   {	  
	  alert(e);
	  //var obj = JSON.parse(e);
//	  document.getElementById("result").innerHTML = e+"<br>";
//	  eventList.appendChild(document.getElementById("result"));
   }, false);
    
   
   $("#Sendbutton").click(function()
   {	    
	  $.ajax(
	  {
		 cache: false,
		 url: 'Daten.json',
		 dataType: "json",
		 success: function(daten) 
		 {
			daten[user][Gegner]="12,80"; 	 /* JSON-Daten verändern*/
		
			$.ajax(         /*und geänderte Daten wieder hochladen*/
			{
			   type: "POST",
			   url: 'update.php',
			   data: {message :JSON.stringify(daten), file: 'Daten.json'}			
			});
		 },
		 error:function()
			   {
				   alert("es ist ein Fehler aufgetreten");
			   } 
	  });
	  
	  
	  $.ajax(                        /* Change.json zum verändern runterladen*/
	  {
		 cache: false,
		 url: 'Change.json',
		 dataType: "json",
		 success: function(data) 
		 {
			data.index++;    /* im Data.index ist die Menge der Änderungen gespeichert. Wird um 1 erhöht*/
			var x={};
			x[data.index]={"user":user,"Gegner":Gegner,"Wert":Wert,"alterWert":alterWert};		 
			data = $.extend(data,x);		 /* Ein neues Objekt hinten angehängt*/
			var y=JSON.stringify(data);
			alert(y);
			$.ajax(         /*und wieder hochladen*/
			{
			   type: "POST",
			   url: 'update.php',
			   data: {message :JSON.stringify(data), file: 'Change.json'},
			   success: function(z)
			   {
				alert(z);  
			   },		   
			   error:function()
			   {
				   /*alert("es ist ein Fehler aufgetreten");*/
			   } 			   
			});
		 }
	  });
	     
   });
});

PHP:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

while (1) 
{  
   $h = fopen('Change.json', 'r');
   if (flock($h, LOCK_EX)) 
   { 
	  $jsondata= fread($h,filesize("Change.json")); /*Datei einlesen*/
	  
	  echo "event: ping\n";
	  echo "data: $jsondata";
	  
	  ob_end_flush();
	  flush();
	 
	  fclose($h);
	  
	  $h = fopen('Change.json', 'w');
	
	  fwrite($h,'{"index":0}'); /* Nur Index=0 in die Datei schreiben*/
	
	  
	 flock($h, LOCK_UN);
   }  
   fclose($h);    
   sleep(1);
}
?>
 
was machen denn die vielen ajax-requests?
  • refresh.php - dein sse-script welches die daten im client updatet
  • ajax-get-request auf Daten.json - ??? was ist das?
  • ajax-post-request auf update.php - script welches dem server änderungen mitteilt
  • noch ein ajax-get-request auf Daten.json - dass der auch vor dem 1. ankommen kann ist dir klar?
  • und noch ein ajax-get-request auf Daten.json - der kommt aber definiert nach dem vorhergehenden an
im refresh.php:
du kannst nicht das file-handle schließen und neu öffnen wenn du das locken willst
 
Zuletzt bearbeitet von einem Moderator:
Nee, da hast du dich verlesen.
1 Get auf Daten.json,
1 Post auf Daten (über Update)
1 Get auf Change.json
1 Post auf Change (über Update)

Hab mal etwas besser kommentiert.
Die Requests auf "Daten.json" kann man hier erstmal beiseite lassen. Die haben mit dem SSE nix zu tun.

Trotzdem zum Verständnis:
Ein User nimmt in seiner Tabelle eine Änderung vor. (Die Gesamtdaten von allen Usern stehen in der "Daten.json")
Die "Daten.json wird runtergeladen, geändert, und wieder hochgeladen.

Dann wird die "Change.json" runtergeladen (sollte normalerweise leer sein, bis auf "Index=0". Nur wenn 2 Änderungen kommen, bevor die Datei runtergeladen wurde, steht da mehr drin)
Die neue Änderung wird angehängt (hier nur ein fiktives Objekt)
Und wieder hochgeladen.

Die "refresh.php" liest ständig die "Change.json" aus, sendet (sollte) die Änderungen per SSE, und löscht den Inhalt der Datei, bis auf "Index=0".

Code:
$(document).on( "pageshow", "#home",function(event) 
{
   var user="Fedi";
   var Gegner="Hubi";
   var Wert='1,00';
   var alterWert='3,00';
   
   var source = new EventSource("refresh.php");
   source.addEventListener("ping", function(e) 
   {	  
	  alert(e);
	  //var obj = JSON.parse(e);
//	  document.getElementById("result").innerHTML = e+"<br>";
//	  eventList.appendChild(document.getElementById("result"));
   }, false);
    
   
   $("#Sendbutton").click(function()
   {	    
	  $.ajax(                                          [COLOR="#008000"] /* Datei "Daten.json" laden[/COLOR]
	  {
		 cache: false,
		 url: 'Daten.json',
		 dataType: "json",
		 success: function(daten) 
		 {
			daten[user][Gegner]="12,80"; 	[COLOR="#008000"] /* JSON-Daten verändern*/[/COLOR]
		
			$.ajax(                           [COLOR="#008000"] /*und geänderte Daten via update.php wieder in die Datei schreiben*/[/COLOR]
			{
			   type: "POST",
			   url: 'update.php',
			   data: {message :JSON.stringify(daten), file: 'Daten.json'}			
			});
		 },
		 error:function()
			   {
				   alert("es ist ein Fehler aufgetreten");
			   } 
	  });
	  
	  
	  $.ajax(                       [COLOR="#008000"] /* Datei "Change.json" zum verändern runterladen. Enthält die noch nicht per SSE gesendeten Änderungen*/[/COLOR]
	  {
		 cache: false,
		 url: 'Change.json',
		 dataType: "json",
		 success: function(data) 
		 {
			data.index++;                                                    [COLOR="#008000"] /* im Data.index ist die Menge der Änderungen gespeichert. Wird um 1 erhöht*/[/COLOR]
			var x={};
			x[data.index]={"user":user,"Gegner":Gegner,"Wert":Wert,"alterWert":alterWert};	[COLOR="#008000"]/* Jetzt zum testen ein neues Objekt anlegen*/	 [/COLOR]
			data = $.extend(data,x);		                                                             [COLOR="#008000"]/* Das neue Objekt hinten angehängt*/[/COLOR]
			var y=JSON.stringify(data);
			alert(y);
			$.ajax(                                                                          
			{
			   type: "POST",                                                                  [COLOR="#008000"] /*und über "update.php" wieder in die "Change.json" geschrieben.*/[/COLOR]
			   url: 'update.php',
			   data: {message :JSON.stringify(data), file: 'Change.json'},
			   success: function(z)
			   {
				alert(z);  
			   },		   
			   error:function()
			   {
				   /*alert("es ist ein Fehler aufgetreten");*/
			   } 			   
			});
		 }
	  });
	     
   });
});

PHP-

- - - Aktualisiert - - -

im refresh.php:
du kannst nicht das file-handle schließen und neu öffnen wenn du das locken willst

Ich wollte verhindern, dass jemand auf die Datei zugreift, bevor ich geschrieben habe.

Ich muss die Datei auslesen, und dann löschen, bis auf den Eintrag "Index=0".
Den Erst lesen-, dann Schreiben-Vorgang, wollte ich zunächst mit $h = fopen('Change.json', '[COLOR="#FF0000"]r+[/COLOR]'); erreichen. Dann hängt er aber hintendran, und die alten Daten bleiben bestehen.
Mit $h = fopen('Change.json', '[COLOR="#FF0000"]w+[/COLOR]'); kann ich scheinbar nur schreiben, und danach wieder auslesen. Nich umgekehrt.

Wie müsste das denn aussehen?
 
Nee, da hast du dich verlesen.
sagen wir falsch kopiert, das letzte get bei mir sollte ein post sein
bleibt die frage, was dass soll.

Ein User nimmt in seiner Tabelle eine Änderung vor. (Die Gesamtdaten von allen Usern stehen in der "Daten.json")
ok

Die "Daten.json wird runtergeladen,
wozu?
geändert, und wieder hochgeladen.
ok

Dann wird die "Change.json" runtergeladen (sollte normalerweise leer sein, bis auf "Index=0". Nur wenn 2 Änderungen kommen, bevor die Datei runtergeladen wurde, steht da mehr drin)
Die neue Änderung wird angehängt (hier nur ein fiktives Objekt)
Und wieder hochgeladen.
wenn das schon über Daten.json geht, warum dann nochmal über Change.json?

das einzige was du meiner meinung nach bei einer änderung machen müsstest, die Change.json zum server senden. bleibt dein sse und ein post.

Die "refresh.php" liest ständig die "Change.json" aus, sendet (sollte) die Änderungen per SSE, und löscht den Inhalt der Datei, bis auf "Index=0".


Wie müsste das denn aussehen?
PHP: fopen - Manual
mit "kann ich scheinbar nur schreiben, und danach wieder auslesen." meinst du, die datei ist leer? ja!

Dann hängt er aber hintendran, und die alten Daten bleiben bestehen.
PHP: ftruncate - Manual
 
Hmm, hab ich da was falsch verstanden? In einem anderen Post von mir hab ich erfahren, dass ich die Datei auf dem Server nur im ganzen ändern kann.
D.h. für mich: Dateiinhalt runterladen, ändern, und wieder hochladen.

In "Daten" sind alle Userdaten. In "Change" nur die Änderungen.
Sonst müsste ich die "Daten" jedesmal auf Änderungen untersuchen.

Meine refresh.php funktioniert immer noch nicht.
Habe jetzt r+ und truncate eingebaut:
PHP:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

//while (1) 
{  $jsondata="";
   $h = fopen('Change.json', 'r+');
   if (flock($h, LOCK_EX)) 
   { 
	  $jsondata= fread($h,filesize("Change.json")); /*Datei einlesen*/
	  echo "event: ping" . "\n\n";
	  echo "data: $jsondata";
	  
	  ob_end_flush();
	  flush();
	  
	  ftruncate($h, 0);
	  fwrite($h,'{"index":0}'); /* Nur Index=0 in die Datei schreiben*/
	
	  
	  flock($h, LOCK_UN);
   }  
   fclose($h); 
   
   sleep(1);
}
?>

Wenn ich nun die "Change.json" öffne, steht tatsächlich nur {"index":0} drin. So wie es sein soll.
Die While-Schleife habe ich deaktiviert, um in der Konsole das "Echo" zu untersuchen. Da kommt folgendes an:
data.gif
Und im Browser kommt immer noch nix an. Auch wenn ich vorübergehend die Variable fürs Echo direkt mit "Test" lade. (In der Konsole kommts dann richtig an)
 
D.h. für mich: Dateiinhalt runterladen, ändern, und wieder hochladen.
warum runterladen - ändern - hochladen? das ist nicht aufgabe des client, sondern des servers. der server wird vom client nur über änderungen informiert.
* der client sendet änderungen an den server
* der server fügt diese änderungen konsistent ein und sendet dann allen clients die aktualisierten daten (oder einfacher - alle daten).

Meine refresh.php funktioniert immer noch nicht.
PHP: fread - Manual
PHP: fseek - Manual
 
So, mein SSE funktioniert jetzt. Nur versteh ichs nicht ganz.
Der Fehler lag hier:
Code:
echo "data: $jsondata[COLOR="#FF0000"]\n\n[/COLOR]";
Ohne \n\n wird nix gesendet. Warum? Das ist doch nur ein Zeilenumbruch :confused:

PHP:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

while (1) 
{  
   $h = fopen('Change.json', 'r+');
   if (flock($h, LOCK_EX)) 
   { 
	  $jsondata=file_get_contents('Change.json');
	  
	  echo "data: $jsondata\n\n";
	  
	  ob_end_flush();
	  flush();
	  fseek($h, 0);
	  ftruncate($h, 0);
	  fwrite($h,'{"index":0}'); /* Nur Index=0 in die Datei schreiben*/	  
	  
	  flock($h, LOCK_UN);
   }  
   fclose($h); 
   
   sleep(1);
}
?>

* der client sendet änderungen an den server
* der server fügt diese änderungen konsistent ein und sendet dann allen clients die aktualisierten daten (oder einfacher - alle daten).

D.h. ich müsste die Änderungen in die "Update.php" schicken, dort die Change.php lesen, Daten ändern und wieder reinschreiben. Also das ganze was ich jetzt auf Clientseite mache, eben Serverseitig.

Oder heißt das, es gibt schon ne fertige routine dafür?
 
Zuletzt bearbeitet von einem Moderator:
So, mein SSE funktioniert jetzt. Nur versteh ichs nicht ganz.
Der Fehler lag hier:
Code:
echo "data: $jsondata[COLOR="#FF0000"]\n\n[/COLOR]";
Ohne \n\n wird nix gesendet. Warum? Das ist doch nur ein Zeilenumbruch :confused:
https://developer.mozilla.org/en-US...er-sent_events#Sending_events_from_the_server

D.h. ich müsste die Änderungen in die "Update.php" schicken, dort die Change.php lesen, Daten ändern und wieder reinschreiben. Also das ganze was ich jetzt auf Clientseite mache, eben Serverseitig.
du sendest die änderungen an Update.php oder ein eigenes php-script change.php, baust diese in die json datei ein und speicherst diese.
Update.php merkt dass die datei sich geändert hat und sendet die änderungen an alle clients
 
So, ich hab jetzt nochmal komplett umgebaut. Ich dachte, jetzt hätte ichs, aber es ergibt sich wieder ein Problem.
Zunächst mal der Aufbau:

Change fällt weg.
Ich mache ein Post über "update.php" und schreibe die Änderung in Daten.json.
Zusätzlich schreibe ich "update":"true" rein.

Refresh liest ständig die Daten.json. Bei update true wird der gesamte Dateiinhalt per SSE gesendet. Und "update" auf "false" gesetzt.

JS:
Code:
$(document).on( "pageshow", "#home",function(event) 
{
   var user="Fedi";
   var Gegner="Hubi";
   var Wert='16,00';   
   var evtSource = new EventSource("refresh.php");

   evtSource.onmessage = function(e) 
   {	 
	  document.getElementById("result").innerHTML = e.data+"<br>";
   };  
    
   $("#Sendbutton").click(function()
   {	      
		 $.ajax(        
		 {
			type: "POST",
			url: 'update.php',
			data: {message :JSON.stringify({"user":user,"Gegner":Gegner,"Wert":Wert}), file: 'Daten.json'},
			success: function(z)
			{
			 
			},		   
			error:function()
			{
				/*alert("es ist ein Fehler aufgetreten");*/
			} 			   
		 });		
   });
});

update.php:
PHP:
<?php 
 
if(isset($_POST)) 
{
   $message = $_POST['message'];
   $file = $_POST['file'];
   header("Refresh:0");
   
   $Obj=json_decode($message); 
   $user=$Obj->user;  
   $Gegner=$Obj->Gegner;
   $Wert=$Obj->Wert;   
  
   $h=fopen($file,'r+');
   if (flock($h, LOCK_EX))   
   {  	    
   	  $Daten=json_decode(file_get_contents($file));	 	  
	  $Daten->$user->$Gegner = $Wert;
	  $Daten->update = "true";
	  fseek($h, 0);
	  ftruncate($h, 0);
	  fwrite($h,json_encode($Daten));   
	  flock($h, LOCK_UN);
   }  
   fclose($h);
   
  
}
?>

refresh.php:
PHP:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

while (1) 
{  
   $jsondata=file_get_contents('Daten.json');
   $obj=json_decode($jsondata);
   
   if($obj->update == "true")
   {   
	  $h = fopen('Daten.json', 'r+');
	  if (flock($h, LOCK_EX)) 
	  { 	 
		 echo "data: $jsondata\n\n";		 
		 ob_end_flush();
		 flush();
		 $obj->update = "false";	  
		 fseek($h, 0);
		 ftruncate($h, 0);
		 fwrite($h,json_encode($obj)); 
	  }
	  flock($h, LOCK_UN);
	  fclose($h);
   }     
   
   sleep(1);
}
?>

Problem: Ich kriege ein Timeout von "refresh".
Liegt das am Code, oder hab ich grad nur zufällig ein Serverproblem?
GET XHR http://www.huberlix.de/abc/refresh.php [HTTP/1.1 504 Gateway Time-out 180024ms]

Hoffe, ich strapaziere deine Geduld nicht zu sehr. Bin sehr dankbar für deine Tips.
 
Ich mache ein Post über "update.php" und schreibe die Änderung in Daten.json.
Zusätzlich schreibe ich "update":"true" rein.
das geht aber wieder nicht mit mehreren änderungen/mehreren clients

generell:
* du musst auch die lesezugriffe locken, sonst kann es dir passieren, dass du gerade etwas liest, was gerade geändert wird, dann kommt datenmüll raus
* das unlock darfst du nur machen wenn das lock funktioniert hat, bei blockierenden flock ist das zwar egal, aber trotzdem unschön (refresh.php)

Problem: Ich kriege ein Timeout von "refresh".
vermutlich liegt das am lock, welches nicht freigegeben wurde, bau mal vor und nach log was ein woran du das erkennst, liegt vielleicht auch an einem vorhergehenden test
funktioniert denn update.php?
 
Jetzt müsste die Reihenfolge fürs Lock stimmen, oder?
Funktioniert jetzt manchmal. Bei Button-click kommen gelegentlich Daten im Browser an. Aber Glücksache.

Kann das sein, das durch die ständigen Locks in der While-Schleife (refresh), die update nicht zum Zuge kommt?

update.php
PHP:
<?php 
 
if(isset($_POST)) 
{
   $message = $_POST['message'];
   $file = $_POST['file'];
   header("Refresh:0");
   
   $Obj=json_decode($message); 
   $user=$Obj->user;  
   $Gegner=$Obj->Gegner;
   $Wert=$Obj->Wert;   
  
   $h=fopen($file,'r+');
   if (flock($h, LOCK_EX))   
   {  	    
   	  $Daten=json_decode(file_get_contents($file));	 	  
	  $Daten->$user->$Gegner = $Wert;
	  $Daten->update = "true";
	  fseek($h, 0);
	  ftruncate($h, 0);
	  fwrite($h,json_encode($Daten));   
	  flock($h, LOCK_UN);
   }  
   fclose($h);
}
?>

refresh.php
PHP:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

while (1) 
{     
   $h = fopen('Daten.json', 'r+');
   if (flock($h, LOCK_EX)) 
   { 	  
	  $jsondata=file_get_contents('Daten.json');
	  var_dump($jsondata);
	  $obj=json_decode($jsondata);
	  var_dump($obj->update);
	  if($obj->update == "true")
	  {   		   
		 echo "data: $jsondata\n\n";		 
		 ob_end_flush();
		 flush();
		 $obj->update = "false";	  
		 fseek($h, 0);
		 ftruncate($h, 0);
		 fwrite($h,json_encode($obj)); 		 
	  }	
	  flock($h, LOCK_UN);  
	  fclose($h);
   }     
   sleep(1);
}
?>
 
Jetzt müsste die Reihenfolge fürs Lock stimmen, oder?
das unlock in refresh machst du immer noch immer und nicht nur wenn das lock auch geklappt hat
prinzipiell kannst du natürlich file_get_contents nehmen im lock, besser wäre du würdest mit fread auf dem gelockten handle arbeiten

Funktioniert jetzt manchmal. Bei Button-click kommen gelegentlich Daten im Browser an. Aber Glücksache.
das bedeutet?

Kann das sein, das durch die ständigen Locks in der While-Schleife (refresh), die update nicht zum Zuge kommt?
da liegen 1 sek zw. den locks, das sind welten, aber da du ja mit mehreren clients rechnen musst, wird das zum problem werden.
refresh darf eigentlich nur lesend auf die datei zugreifen und könnte dann mit multi-read-lock arbeiten.
 
Hmmm, heute morgen funktionierts einwandfrei. Vielleich gabs bei 1&1 doch ein Serverproblem

- - - Aktualisiert - - -

das unlock in refresh machst du immer noch immer und nicht nur wenn das lock auch geklappt hat

das unlock ist doch in derif (flock....-abfrage.
Hast du bestimmt übersehen, weil da ein zweites if ist.
PHP:
if (flock($h, LOCK_EX)) 
   { 	  
	  $jsondata=file_get_contents('Daten.json');
	  var_dump($jsondata);
	  $obj=json_decode($jsondata);
	  var_dump($obj->update);
	  if($obj->update == "true")
	  {   		   
		 echo "data: $jsondata\n\n";		 
		 ob_end_flush();
		 flush();
		 $obj->update = "false";	  
		 fseek($h, 0);
		 ftruncate($h, 0);
		 fwrite($h,json_encode($obj)); 		 
	  }	
	  flock($h, LOCK_UN);  
	  fclose($h);
   }

prinzipiell kannst du natürlich file_get_contents nehmen im lock, besser wäre du würdest mit fread auf dem gelockten handle arbeiten

Naja in der Beschreibung von fread() steht folgendes:
Anmerkungen ¶

Hinweis:

Wenn man nur den Inhalt einer Datei in eine Zeichenkette lesen will, so sollte man file_get_contents() verwenden, da dies eine bessere Performance hat als der obige Code.



Ich zeige die SSE-Daten im Browser an. wenn ich per Button-klick ein update mache, kamen nur ab und zu Daten an.
Aber jetzt gehts.
Hatte den Code kurz geändert, dass ein Wert bei jedem update um 1 erhöht wird, zum testen.
Habe jetzt sogar mehrmals in der Sekunde upgedatet. Dann überspringt er natürlich 1-2 SSE, wegen dem Sleep(1). Aber das letzte Update wird angezeigt. Da ich jetzt alle Daten zum Client schicke, und dort später pro User rausfiltere, ist das OK so.


da liegen 1 sek zw. den locks, das sind welten, aber da du ja mit mehreren clients rechnen musst, wird das zum problem werden.
Pro Spiel tragen immer nur 4 Leute Daten ein. Ich denk, da gibts kein Problem.

refresh darf eigentlich nur lesend auf die datei zugreifen und könnte dann mit multi-read-lock arbeiten.
Muss ja aber in der Datei den Wert "Update" wieder auf "false" setzen.
 
Zurück
Oben