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

[FRAGE] socket.io und client Verwaltung??

Hallo,

so da bin ich mit meinem laufendem Server wieder =)

Code:
var server = require('http').createServer();
var io = require('socket.io').listen('8080'),
    mysql = require("mysql"),
    squel = require("squel"),
    memcache = require("memcache");
    //client = require('socket.io-client');
	
// memcache Verbindung herstellen
var cache = new memcache.Client(11211, "localhost");
cache.connect();

// lobby.clients.{uid}
var lobby = new function(){
	this.clients={}; // user instanzen werden hier in die user php-uid abgelegt welche auch als index genutzt wird
	this.sid={}; // hier gilt die socket.id als index und enthält jeweils die php-uid
	this.gChats={}; // hier listen wir aktive gruppen chats bzw. nur die user einer gruppe die online sind um an diese auszuliefern
	this.cnt = '';
	
	this.addClient = function(data, socketID, sessID)
	{
		var userData = JSON.parse(data);
		if( userData.sid != '' ) // check of exist socket-id
		{
			this.updateSid(userData.sid, socketID, userData.uid); // update session to new socket-ID
			userData.sid = socketID;
			userData.sessKey = sessID; // muss für die js-Instanz wieder hinzugefügt werden
			userData.lastAct = new Date().toString(); // muss für die js-Instanz wieder hinzugefügt werden
			this.clients[userData.uid] = userData;
		}
		else // der user hat noch keine sid, er ist also das erste mal in der session mit socket verbunden
		{
			userData.sid = socketID;
			userData.sessKey = sessID;
			userData.lastAct = new Date().toString();
			this.clients[userData.uid] = userData;
			this.sid[socketID] = userData.uid;
		}
		// php-sess updaten, nach jedem lobby.addClient
		delete userData.sessKey; // will not need on php-sess
		delete userData.lastAct; // will not need on php-sess
		cache.set('socketSess/'+sessID, JSON.stringify(userData), function(err, response) { /** Schreibvorgang kann hier geprüft werden */ });
		//console.log( 'user added: '+JSON.stringify(userData) );
	}
	
	this.updateSid = function(oldSid, newSid, uid)
	{
		delete this.sid[oldSid]; // rem old socket.id from sid list
		this.sid[newSid] = uid; // set new socket.id and add the owner
	}
	
	this.remClient = function(socketID)
	{
		var uid = this.sid[socketID];
		console.log('remClient: '+ uid);
		console.log('remSid: '+ socketID);
		delete this.clients[uid]; // remove client
		delete this.sid[socketID]; // remove sid
	}
	
	this.addToGchat = function(userData)
	{
		// hier kommt später das zeug den user in ein gruppen chat hinzuzufügen
	}
};

// Create a Socket.IO instance, passing it our server
var socket = io.listen(server);
socket = socket.of('/root'); // set namespace
socket.on('connection', function(socket, error)
{
	socket.on('auth', function(sessID, error)
	{
		// auth erfolgt via memcache über die abzurufende session
		cache.get('socketSess/'+decodeURIComponent(sessID), function(error, result)
		{
			if( typeof(error)==="undefined" ) // ist ein memcache error aufgetretten erfolgt kein user.add
			{
				if( typeof(result)!=="undefined" && result != null ) // kein error nun prüfe die erhaltenen Daten
				{
					lobby.addClient( result, socket.id, sessID ); // sende json string und sid + sessID an die addClient funktion
				}
				else{ console.log('no PHP-session found'); } // erhaltene session war fehlerhaft, abbruch!
			}else{ 
				console.log("error : "+error);
			}
		});
	});

	socket.on('disconnect', function(sessID){
		lobby.remClient( socket.id );
	});
	
	socket.on('stefClick', function(data)
	{
		var empfaenger = lobby.clients[1]['sid'];
		console.log('sende msg to: '+ empfaenger);
		//io.sockets.connected[empfaenger].emit("testReceive", "Ich klicke du empfängst!");
		io.sockets.of('/root').connected[empfaenger].emit("testReceive", {msg: "Ich klicke du empfängst!"} );
	});
});
console.log('Juhu Server running');

klappt alles bis dahin wie ich es gerne hätte was das user handling angeht aber nun bin ich bei dem Thema der Zielgerichteten emits...
Code:
socket.on('stefClick', function(data)
	{
		var empfaenger = lobby.clients[1]['sid'];
		console.log('sende msg to: '+ empfaenger);
		//io.sockets.connected[empfaenger].emit("testReceive", "Ich klicke du empfängst!");
		io.sockets.of('/root').connected[empfaenger].emit("testReceive", {msg: "Ich klicke du empfängst!"} );
	});

ein Fehler taucht nicht auf, auch in putty erhalte ich die Ausgabe das er zu dem user sendet nur ankommen tut nichts =(
Wäre dir da echt Dankbar wenn Du mich auf nen Fehler hinweisen würdest.

Das nachstehende Thema sind dann die räume auf socket ebene, ich würde gerne mit der Webseite eindeutige ID,s für gurppenchats anlegen so das ich dan mit meinem Clienthandler bei bedarf nen user in einen Raum adden kann und die socket Funktion nutzten um an alle listner zu senden.
Mit meinem handler könnte ich es auch realisieren, würde aber deutlich umständlicher sein da ich per foreach() alle listener abarbeiten würde und persönliche emit schicken, da sollte ich also doch lieber die Funktionen von socket.io nutzten.

MFG: Paykoman

::EDIT:: Nun jetzt haut er mir doch ne Fehlermeldung raus, die bringt uns aber nicht weiter ma müssten erstmal einen errorhanlder definieren, hab aber kein Schimmer wie =(
Code:
Missing error handler on `socket`.
TypeError: undefined is not a function
    at Socket.<anonymous> (/home/wposrv/socket/node_modules/socket.io/lib/app.js:127:14)
    at Socket.emit (events.js:107:17)
    at Socket.onevent (/home/wposrv/socket/node_modules/socket.io/lib/socket.js:330:8)
    at Socket.onpacket (/home/wposrv/socket/node_modules/socket.io/lib/socket.js:290:12)
    at Client.ondecoded (/home/wposrv/socket/node_modules/socket.io/lib/client.js:193:14)
    at Decoder.Emitter.emit (/home/wposrv/socket/node_modules/socket.io/node_modules/socket.io-parser/node_modules/component-emitter/index.js:134:20)
    at Decoder.add (/home/wposrv/socket/node_modules/socket.io/node_modules/socket.io-parser/index.js:247:12)
    at Client.ondata (/home/wposrv/socket/node_modules/socket.io/lib/client.js:175:18)
    at Socket.emit (events.js:107:17)
    at Socket.onPacket (/home/wposrv/socket/node_modules/socket.io/node_modules/engine.io/lib/socket.js:99:14)

hab auch schon nach "Missing error handler on `socket`." gegoogelt aber nichts hilfreiches gefunden =(
 
Zuletzt bearbeitet:
Code:
io.[B]sockets[/B].of('/root').connected[empfaenger].emit("testReceive", {msg: "Ich klicke du empfängst!"} );
was ist io.sockets?
 
nagut io.of()... funktioniert.

Sehr schön wieer eins von der Liste streichen =)
Nun an die Gruppen umsetzung, haste da nen Tipp für mich was ich beachten sollte?
 
Zuletzt bearbeitet:
Code:
// Require HTTP module (to start server) and Socket.IO
var http = require('http');
var url = require('url'); 
var fs = require('fs'); 
var port = 8080;

// Start the server at port 8080
var server = http.createServer(handler);
server.listen(port);

function handler (request, response)
{
  console.log(request.url);
  if (request.url == '/')
  {
    fs.readFile(__dirname + '/index.html', 'utf-8', function (error, data)
    {
      if (error)
      {
        response.writeHead(500);
        return response.end('Error loading index.html');
      }
      response.writeHead(200);
      response.end(data);
    });
  }
  else
  {
    fs.readFile(__dirname + request.url, 'utf-8', function (error, data)
    {
      if (error)
      {
        response.writeHead(500);
        return response.end('Error loading ' + request.url);
      }
      response.writeHead(200);
      response.end(data);
    });
  }
}

// Create a Socket.IO instance, passing it our server
var io = require('socket.io')();
io.listen(server);
 
// Add a connect listener
var nsp = io.of('/test');
nsp.on('connection', function(socket)
{
  socket.on('test', function (data)
  {
    console.log(nsp.connected[socket.id] === socket);
    console.log('testdata: ' + data);
    nsp.emit('test', 'aloha');
    io.of('/test').connected[socket.id].emit('me', "only to you" );
  });
});

Code:
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <script src="socket.io.js"></script>
    <script>
      var socket = io.connect(location.host + '/test', { forceNew: true });
      socket.on('connect', function ()
      {
        socket.emit('test', 'huhu');
        socket.on('test', function (data)
        {
          console.log('testdata: ' + data);
        });
        socket.on('me', function (data)
        {
          console.log('testdata: ' + data);
        });
      });
    </script>
  </head>
  <body>
    
  </body>
</html>

- - - Aktualisiert - - -

Nun an die Gruppen umsetzung, haste da nen Tipp für mich was ich beachten sollte?
http://socket.io/docs/rooms-and-namespaces/#rooms
 
Wozu denn nun das Beispiel mit dem handler?
Ik nutz doch garkein :(

Es klappt aber jetzt auch das soweit, auch das mit den rooms, hätte da nur noch eine Frage dann haben wir es durch denke ich...
Verwaltet wird das ganze ja einfach mit "socket.join(room);" für das beitreten und "socket.leave(room);" für das verlassen, habe das mal durch gespielt und mir scheint der leere Raum bleibt offen, geht er automatisch iwann zu?

Nicht das mein Server iwann zugepackt ist mit leeren Räumen :(


::EDIT::
Eine Sache hätte ich doch noch, da ich ja nun auch clientseitig beim connecten die Funktion ausführe, erscheint beim beenden des socket-server eine Fehlermeldung in der Browsercconsole des clients
Uncaught RangeError: Maximum call stack size exceeded

Klar weil er versucht ja zu reconnecten, am Anfang mit dem Basis Server hat das soweit aber ohne diese Fehlermeldung geklappt und sobald der Server wieder lief waren die User wieder verbunden.
Da stehe ich einwenig auf dem Schlauch wie ich das Thema angehen soll.
 
Zuletzt bearbeitet:
Wozu denn nun das Beispiel mit dem handler?
Ik nutz doch garkein :(
weil ein nachvollziehbares minimalbeispiel numal auch normale requests bedienen muss.
dass du dass über php machtst aber es in diesem beispiel auch über node läuft, spielt ja für das problem selbst keine rolle.

habe das mal durch gespielt und mir scheint der leere Raum bleibt offen, geht er automatisch iwann zu?
was heißt es "scheint" so zu sein? woran machst du das fest?

Eine Sache hätte ich doch noch, da ich ja nun auch clientseitig beim connecten die Funktion ausführe, erscheint beim beenden des socket-server eine Fehlermeldung in der Browsercconsole des clients
ich kenne deinen clientcode nicht

Klar weil er versucht ja zu reconnecten, am Anfang mit dem Basis Server hat das soweit aber ohne diese Fehlermeldung geklappt und sobald der Server wieder lief waren die User wieder verbunden.
was war der basis server? wo ging es noch, wo nicht?
 
Hi, jut ich poste noch mal den Server und den Client

Server:
Code:
var server = require('http').createServer();
var io = require('socket.io').listen('8080'),
    mysql = require("mysql"),
    squel = require("squel"),
    memcache = require("memcache");
    //client = require('socket.io-client');
	
// memcache Verbindung herstellen
var cache = new memcache.Client(11211, "localhost");
cache.connect();

// lobby.clients.{uid}
var lobby = new function(){
	this.clients={}; // user instanzen werden hier in die user php-uid abgelegt welche auch als index genutzt wird
	this.sid={}; // hier gilt die socket.id als index und enthält jeweils die php-uid
	
	this.addClient = function(data, socketID, sessID)
	{
		var userData = JSON.parse(data);
		if( userData.sid != '' ) // check of exist socket-id - user is listed update this user
		{
			// JS-Instanz vorbereiten
			delete this.sid[userData.sid]; // rem old socket.id from sid list
			this.sid[socketID] = userData.uid; // set new socket.id and add the owner
			// Daten preparieren
			userData.sid = socketID; // neue socket id speichern
			userData.sessKey = sessID; // muss für die js-Instanz wieder hinzugefügt werden
			userData.lastAct = new Date().toString(); // muss für die js-Instanz wieder hinzugefügt werden
			this.clients[userData.uid] = userData; // session in instanz speichern
		}
		else // der user hat noch keine sid, er ist also das erste mal in der session mit socket verbunden
		{
			userData.sid = socketID;
			userData.sessKey = sessID;
			userData.lastAct = new Date().toString();
			this.clients[userData.uid] = userData;
			this.sid[socketID] = userData.uid;
		}
		// php-sess updaten, nach jedem lobby.addClient
		delete userData.sessKey; // will not need on php-sess
		delete userData.lastAct; // will not need on php-sess
		cache.set('socketSess/'+sessID, JSON.stringify(userData), function(err, response) { /** Schreibvorgang kann hier geprüft werden */ });
		console.log('Client ('+socketID+') with u-ID ('+userData.uid+') has connected');
	}
	
	this.remClient = function(socketID)
	{
		var uid = this.sid[socketID];
		// console.log('remClient: '+ uid);
		// console.log('remSid: '+ socketID);
		delete this.clients[uid]; // remove client
		delete this.sid[socketID]; // remove sid
	}
	
	this.getData = function(sID, key) // socket ID
	{
		if( typeof this.sid[sID] != 'undefined' )
		{
			var uID = this.sid[sID];
			if( typeof this.clients[uID][key] != 'undefined' ){ return this.clients[uID][key]; }
		}
		else{ return false; }
	}
	
	this.addToGchat = function(userData)
	{
		// hier kommt später das zeug den user in ein gruppen chat hinzuzufügen
	}
	
	this.getSession = function(sessID, socketID)
	{
		cache.get('socketSess/'+decodeURIComponent(sessID), function(error, result)
		{
			if( typeof(error)==="undefined" ) // ist ein memcache error aufgetretten erfolgt kein user.add
			{
				if( typeof(result)!=="undefined" && result != null ) // kein error nun prüfe die erhaltenen Daten
				{
					lobby.addClient( result, socketID, sessID ); // sende json string und sid + sessID an die addClient funktion
				}
				else{ console.log('Client not added, no PHP-session found!'); } // erhaltene session war fehlerhaft, abbruch!
			}else{ 
				console.log("error : "+error);
			}
		});
	}
};

// Create a Socket.IO instance, passing it our server
var socket = io.listen(server);
socket = socket.of('/root'); // set namespace
socket.on('connection', function(socket)
{
	socket.on('auth', function(sessID){ lobby.getSession(sessID, socket.id); }); // auth erfolgt via memcache über die abzurufende session
	socket.on('disconnect', function(){ lobby.remClient( socket.id ); }); // entferne Client aus der Instanz beim verlassen der Seite
	socket.on('getContacts', function(){ console.log( lobby.getData(socket.id, 'contacts') ); }); / aktuelel Baustelle :D
	
});

Client:
Code:
// die connection selbst ist hier nicht drin habe das im quellcode verankert (vor </bod>)!
/**
<script src='http://domain.tld:8080/socket.io/socket.io.js'></script>
    <script type='text/javaScript'>var socket = new io.connect('http://domain.tld:8080/root');</script>
    <script src='/myproject/app/plugins/dashboard/dashboard.client.js' type='text/javascript'></script>
</body>
</html>

nun folgt die dashboard.client.js
*/

socket.on('connect',function() {
    socket.emit('auth', getCookie('WPOCMS') );
});

socket.on('getContactDatas', function(data)
{
    // erhalte contactliste erstelle Elemente..
});

socket.on('disconnect',function() {
    socket.emit('disconnect');
});

Ist halt jetzt auch noch nicht so viel, letze Woche drehte sich ja mehr alles um den server und das client handling, so fange ich gerade erst an die Strukturen zu errichten.
Nun ich hatte console.log( io.of('/root').in(room) ); gemacht und obwohl niemand drin war gabs ne Lange liste als ausgabe bit dem object clients das natürlich leer war, kann aber ja sein das es nen proto war oder so und da immer ne Ausgabe kommt.


Mich interessiert das mit den Räumen halt zwecks Gruppen chats und heute ist wohl der "Onlinestatus" an sich hinzu gekommen...
Wen man eine interaktive Kontaktliste macht, muss jeder client beim dissconnecten eigentlich all seine Freunde (die wo online sind) per emit mitteilen das er nun offline ist und da wären Räume vllt. auch von vorteil. Z.B. beim connecten erhält jeder einen eigenen Raum, Freunde die bereits on sind werden zu dem Raum hinzugefügt und die die später online kommen auch. so bräuchte man nur ne funktion wenn der owner den Raum verlässt eben automatisch an alle via emit am ganzen Raum informiert werden.

Aber wie gesagt kenn mich mit den Funktionen von socket.io nicht so aus und die DoKu, naja hatten wir schon =)
Wenn es da vergleich bares gibt wäre das nämlich einfacher und unkomplizierter als dafür wieder eigene tracking funktionen zu schreiben.


MFG: Pay
PS: einfach paar coole room-commands nennen oder sowas *gg*
 
Zuletzt bearbeitet:
ich könnte mir vorstellen, dass das
Code:
socket.on('disconnect',function() {
    socket.emit('disconnect');
});
zu deinem fehler führt. 1. kannst du nach einem disconnect nichts mehr senden, und 2. bekommet der server das disconnect ja auch so

Nun ich hatte console.log( io.of('/root').in(room) ); gemacht und obwohl niemand drin war gabs ne Lange liste als ausgabe
.in(room) gibt this zurück, deine ausgabe war das Namespace-objekt welches io.of('/root') liefert
Code:
Namespace.prototype['in'] = function(name){
  this.rooms = this.rooms || [];
  if (!~this.rooms.indexOf(name)) this.rooms.push(name);
  return this;
};

Mich interessiert das mit den Räumen halt zwecks Gruppen chats und heute ist wohl der "Onlinestatus" an sich hinzu gekommen...
Wen man eine interaktive Kontaktliste macht, muss jeder client beim dissconnecten eigentlich all seine Freunde (die wo online sind) per emit mitteilen das er nun offline ist und da wären Räume vllt. auch von vorteil. Z.B. beim connecten erhält jeder einen eigenen Raum, Freunde die bereits on sind werden zu dem Raum hinzugefügt und die die später online kommen auch. so bräuchte man nur ne funktion wenn der owner den Raum verlässt eben automatisch an alle via emit am ganzen Raum informiert werden.
du benötigst doch sowieso irgendwo eine freundesliste, da kannst du die doch auch einfach nutzen, um deinen status zu senden an alle die wo online sind mit alles

einfach paar coole room-commands nennen oder sowas *gg*
join/leave und dann broadcast/to/in, mehr ist da nicht
 
Gutti das mit disconnect teste ich mal also auch das mit dem prototyp, das mit dem zurückgelieferten Raum wäre aber komisch, wenn er /root zurückgeliefert hat, hätte er aber bei clients kein leeres array liefern dürfen?
Naja wie gesagt werde das später noch mal unter die Lupe nehmen.

Nun also mit broadcast würden wir wieder ein neues Kapitel öffnen, das hab ich noch garnicht benutzt.
join/leave kenne ich ja schon, und würde ich ja dann auch benutzten so das alle Freunde gleichzeitig benachrichtigt werden. Was fehlen würde ist wenn der owner also dem zugehörigen user denn Channel verlässt weil er zb. offline geht das dann die Clients des Channels informiert werden, klar ein emit() an dem ganzen Raum, worauf ich hinaus wollte ist ob es eine Funktion gibt die mir automatisch meldet das der owner den raum verlassen hat...

Oder nutzte ich da eben besser die eigene dissconnect-Funktion?
So das wenn der client disconnect emitted ich eben den user channel öffne und dem channel sage nun ist er offline...
So wüssten auch alle freunde gleichzeitig das er jetzt offline ist...

Das gleiche könnte man dann auch bei den feeds machen, würde den Server doch sehr entlassen als per for()-Schleife alle Abonnenten abzuarbeiten die online sind und ihnen das Zeug zu übermitteln.
Oder sind channels zu anspruchsvoll das man besser nicht für jeden Client einen eigenen channel erstellen sollte?

Ik muss ja nicht selbst was ausdenken falls es schon Funktionen dafür gibt...

Ein Kumpel sagt, das jeder client automatisch beim connecten bereits ein eigenen channel erhält, stimmt das? Dann muss ik ja kein erstellen und dann nur wissen wie man da joint...

- - - Aktualisiert - - -

Also einiges hat sich erledigt, ja user haben automatisch nen eigenen Raum (wenn ich das richtig gesehen habe), ich werde es über meine connect und disconnect Funktionen steuern.

Was ich aktuell brauche aber leider nicht finde, ist ein Befehl einen Client an Hand seiner socket.id in einen channel zu joinen.
Ich habe bereits 2 Listen die ja sowohl meine phpid als auch die socket.id listen darüber kann ich mir jederzeit die socket.id von einem user holen, nur wie füge ich den in den channel ein?
socket.join(room); lässt ja den eigenen client iwo joinen aber da müsste ich erst an jedem client ein emit senden so das von jedem client aus ein weiterer emit zum server folgt welcher den client dann in mein channel packt, ist aber argh unschön, einfacher wäre halt sowas wie socket.user('4711').join(room);
 
Zuletzt bearbeitet:
Gutti das mit disconnect teste ich mal also auch das mit dem prototyp, das mit dem zurückgelieferten Raum wäre aber komisch, wenn er /root zurückgeliefert hat, hätte er aber bei clients kein leeres array liefern dürfen?
was für ein array? in liefert den namespace, clients bzw. connected den socket

worauf ich hinaus wollte ist ob es eine Funktion gibt die mir automatisch meldet das der owner den raum verlassen hat...
dass musst du ja machen, also du rufst ja socket.leave auf, dann hast du es ja schon

Oder nutzte ich da eben besser die eigene dissconnect-Funktion?
dissconnect kommt, wenn der client die verbindung verliert, das ist was anderes als den raum zu verlassen, kommt drauf an was du möchtest

Das gleiche könnte man dann auch bei den feeds machen, würde den Server doch sehr entlassen als per for()-Schleife alle Abonnenten abzuarbeiten die online sind und ihnen das Zeug zu übermitteln.
ein broadcast macht das genau so, bzw. muss man nicht erst ermitteln, wer online ist. ist man connected, existiert ein socket, sonst nicht

Oder sind channels zu anspruchsvoll das man besser nicht für jeden Client einen eigenen channel erstellen sollte?
wozu für jeden client einen eigenen raum? ich denke du willst es an den "freunde"-raum senden?
aber selbst wenn das sinn machen sollte, den gibt es schon Socket.IO

Ein Kumpel sagt, das jeder client automatisch beim connecten bereits ein eigenen channel erhält, stimmt das? Dann muss ik ja kein erstellen und dann nur wissen wie man da joint...
... ähm ja, stimmt, aber der ist nicht zum joinen, sondern um einem best. socket etwas zu senden

Also einiges hat sich erledigt, ja user haben automatisch nen eigenen Raum (wenn ich das richtig gesehen habe)
... mhhh ja

Was ich aktuell brauche aber leider nicht finde, ist ein Befehl einen Client an Hand seiner socket.id in einen channel zu joinen.
nee, wozu? wenn du daraus deinen "freunderaum" machen willst, das ist der falsche weg

Ich habe bereits 2 Listen die ja sowohl meine phpid als auch die socket.id listen darüber kann ich mir jederzeit die socket.id von einem user holen, nur wie füge ich den in den channel ein?
wenn der andere socket in den "freunderaum" will, sollte dessen client diesen beitritt veranlassen, willst du soetwas wie eine einladung realisieren, schicke an den anderen socket diese einladung, der benachrichtigt dann seinen client und dieser entscheidet dann, ob er beitreten will oder nicht

socket.join(room); lässt ja den eigenen client iwo joinen aber da müsste ich erst an jedem client ein emit senden so das von jedem client aus ein weiterer emit zum server folgt welcher den client dann in mein channel packt, ist aber argh unschön
nee, finde ich so genau richtig - für eine einladung

einfacher wäre halt sowas wie socket.user('4711').join(room);
machbar ist das, du hast ja auf dem server alle sockets in der hand, aber meiner meinung nach falsch
 
gut ok, muss mir da noch ein paar Gedanken machen wie ich es nun umsetze...

Ja, Ziel ist halt Freundes und Abonnenten-kreis zu bilden.

Da bleibt ja eigentlich nur übrig es nach wie vor über 3 Ecken zu machen.

1) User connected, erhält seinen eigenen Raum als auch seine Kontaktliste und die Liste seiner Abonenten, es wird geprüft wer online ist. Nun wird jedem der online ist ein emit geschickt: "hey ich bin online".

2) nun sendet jeder Empfänger wieder ein emit zum server zurück zwecks Raumbeitritt

3) server fügt den user in den Raum hinzu so das diese bei Neuigkeiten informiert wird


Finde ich halt umständlich, da wenn ein user online kommt, ja bereits eine liste hat mit abonnenten zb. dann einfach eine foreach() und die user hinzufügen. Ein Abo besteht ja nur dann wenn man infos möchte also sagt der client ja schon im vorfelt das er joinen möchte, dazu dann erst den client emiten der dann den server zurück emitet macht nicht nur viel traffic sondern ist es auch unschön :)

- - - Aktualisiert - - -

Bei broadcast kenne ich halt die Unterschiede nicht, hier muss der client doch sicher auch iwie erst joinen? Oder kann man bei broadcast eine eigene liste (socket.id`s) als empfänger hinzu fügen?
 
Zuletzt bearbeitet:
Ziel ist halt Freundes und Abonnenten-kreis zu bilden.
ahh, jetzt ...
ok, dann mach eine globalen raum in den jeder der online kommt eine msg schickt, darauf kann jeder lauschen und wenn jemand online kommt, den man aboniert hat, tritt man darauf dessen abo-raum bei

Bei broadcast kenne ich halt die Unterschiede nicht, hier muss der client doch sicher auch iwie erst joinen? Oder kann man bei broadcast eine eigene liste (socket.id`s) als empfänger hinzu fügen?
nee, geht an den raum, aber wie gesagt, das macht auch nichts anderes, als eine liste mit sockets durchzugehen und jedem eine msg zu schicken

- - - Aktualisiert - - -

soweit ich das sehe hast du über use
doch die möglichkeit den 1. request abzufangen, damit kommst du dann auch an deine session-id

ok, dann mach eine globalen raum in den jeder der online kommt eine msg schickt, darauf kann jeder lauschen und wenn jemand online kommt, den man aboniert hat, tritt man darauf dessen abo-raum bei
oder da das ja eher serverinformationen sind und du ja sowieso eine verwaltung der abos und sockets benötigst, diese verwaltung also auch mitbekommt, dass ein neuer client sich verbunden hat, kann diese verwaltung also auch gleich das beitreten der abbo-räume durchführen
 
oder da das ja eher serverinformationen sind und du ja sowieso eine verwaltung der abos und sockets benötigst, diese verwaltung also auch mitbekommt, dass ein neuer client sich verbunden hat, kann diese verwaltung also auch gleich das beitreten der abbo-räume durchführen

ja so ist es ja geplant, immer wenn ein client connected läuft es ja eh über meine erstellte lobby class() durch diese class kann ich dann eben auch auf andere socket`s zugreifen bzw. aktuell alle benötigten ID,s sind redundant erreichbar.

Ich denke die Freundeskreise bekomme ich noch relativ gut umgesetzt, das kann ich dann ja wie oben beschrieben machen:

1) user connectetd und joint sein eigenen Raum zb ucr_{id}
2) Die Kontaktliste wird abgearbeitet, jeder Kontakt der online ist joint in den Raum des users der online kam gleichzeitig joint der user in den Raum des kontaktes (bidirectionale kommunikation gesichert)
3) user sendet an seinen Raum "bin online", bei allen anderen ändert der Status auf On, geht jetzt einer der kontakte offline wird er nur seinem eigenen Raum mitteilen das er off und schwupp die wupps sind alle informiert...


Die Abonnenten dagegen finde ich etwas aufwendiger, dies kann man einwenig mit Facebook vergleichen, jede User kann eigene "Seiten" (ist bei mir zwar anders aber um die Übersicht zu wahren...) erstellen die eben abonniert werden können. Da Abonnenten durch aus schon mal in die tausende gehen können sollte hier natürlich mit Köpfchen gearbeitet werden, klar von 10.000 Abos werden natürlich immer nur ein kleiner Prozentwert online sein, aber dennoch blöd zu handhaben.

Da die "Seiten" selbst nicht als client auf socket.io connecten kann man hier nicht einfach ne liste abarbeiten und joinen.
Spontan fällt mir da nur ein das es wohl das beste wäre gleich beim connecten auch eine liste der abos mit zuliefern, so das man direkt in dessen räume joint, würde bedeuten das jeder Seiten-Raum wieder redundant verfügbar wäre und sich die Anzahl der Räume auf den Server stark summieren. Wenn eine "Seite" etwas postet wäre jedoch die Empfängerliste jederzeit zur Kommunikation bereit und enthält natürlich nur die online user an denen content ausgeliefert werden muss.

Die Frage ist ob zu viele Räume den Server überlasten können? Wenn 1000 user online sind haben wir schon 1000 Räume für das Kontaktnetzwerk und dann jeweils ein Raum aller abonnierten Seiten der 1000 user (also je Seite ein Raum) o_O

Bei einer zweiten Variante müsste man auch beim connecten die abo-liste mit senden so das man ein array der abos in der lobby ablegt und wenn eine Seite etwas postet muss diese eben abgearbeitet werden.

könnte dann so aussehen:
Code:
var lobby = new function(){
	this.clients={}; // user instanzen werden hier in die user php-uid abgelegt welche auch als index genutzt wird
	this.sid={}; // hier gillt die socket.id als index und enthält jeweils die php-uid
	this.abos={}; 
	// wird dann so strukturiert
	this.abos = {
		site.id: {u.id: 'listn', u.id: 'listn', u.id: 'listn', u.id: 'listn'},
		site.id: {u.id: 'listn', u.id: 'listn', u.id: 'listn', u.id: 'listn'},
		site.id: {u.id: 'listn', u.id: 'listn', u.id: 'listn', u.id: 'listn'}
	};
};

die keys sind dann natürlich dynamisch, so das in der Hauptebene die ID der "Seite" ist und in der zweiten Ebene als array keys die user id`s der Webseite enthält und als value kommt die socket.id.
So kann man bequem jeden user ein/austragen wenn einer joint und die "Seiten" hätten auch eine redundante Empfängerliste.
Ich schätze mal das diese Variante sogar den Server weniger belasten würde als die Räume, wenn ich mir einen Raum per console ausgeben lasse enthalten diese ja immer eine riesige klasse (Instanz) die großteils eh nicht genutzt wird aber die Instanzen für jeden user Raum benötigen ja dennoch Ihren Platz im Arbeitsspeicher oder wo auch immer solche Instanzen auf dem Server gespeichert werden.

Ja alles nicht so einfach :-(

PS: hat iwer denn schon mal nachgesehen oder sich erkundigt wie ein Raum-emit() von der mechanik her funktioniert?
Ich könnte mir halt vorstellen das ein Raum eben gleichzeitig eine Verbindung zu alle clients hat und eben nicht jeden einzeln emited wie es eine foreach() solcher Empfängerlisten tun würde und dann fände ich wären Räume vorzuziehen!
 
Zuletzt bearbeitet:
hat iwer denn schon mal nachgesehen oder sich erkundigt wie ein Raum-emit() von der mechanik her funktioniert?
sagte ich doch, es wird uber alle sockets gegangen, die in diesem raum sind und über diese die msg an die clients gesendet

Ich könnte mir halt vorstellen das ein Raum eben gleichzeitig eine Verbindung zu alle clients hat und eben nicht jeden einzeln emited wie es eine foreach() solcher Empfängerlisten tun würde
wenn wir hier über einen broadcast reden, ist das ja kein echter broadcast, sondern das senden an alle verbundenen clients.
 
Zuletzt bearbeitet von einem Moderator:
sagte ich doch, es wird uber alle sockets gegangen, die in diesem raum sind und über diese die msg an die clients gesendet
Ja das habe ich nicht vergessen. Aber wie erwähnt ist es sicher möglich das socket.io alle gleichzeitig ansprechen kann je nach Architektur von socket.io und nicht alle verbundenen sockets per foreach() abarbeitet und dann eben doch wieder jeden einzelnd emited, in letzterem Fall könnte man dann wirklich eigene Listen machen.


wenn wir hier über einen broadcast reden, ist das ja kein echter broadcast, sondern das senden an alle verbundenen clients.

Was genau meinst du mit broadcast? Das übermitteln von streams als webcams/videos und der gleichen? Ein Broadcast ist eben genau sowas für mich und ein Webradio.
Bei mir gehts lediglich um Webseiten-Inhalte (Beiträge, Chat usw.) und online-status.

Ich verwende ja nun auch keine broadcast Funktion von socket da müsste ich erst googlen wie das dann geht bzgl senden/empfang.
 
Aber wie erwähnt ist es sicher möglich das socket.io alle gleichzeitig ansprechen kann je nach Architektur von socket.io
nein, das ist eben nicht möglich, aufgrund der Architektur von (web-)sockets



Was genau meinst du mit broadcast?
https://de.wikipedia.org/wiki/Broadcast

Ich verwende ja nun auch keine broadcast Funktion von socket da müsste ich erst googlen wie das dann geht bzgl senden/empfang.
aber emit an einem namespace, was inhaltlich das gleiche ist (und intern auch wieder broadcast aufruft).
 
Gut also doch eigene listen und call-Funktionen =) Dann machen wa uns mal an die Arbeit!

- - - Aktualisiert - - -

So mein erster Entwurf die Auslieferung zu managen, über eine dafür vorgesehene Funktion so das sich die socket.on()-Funktionen nicht damit beschäftigen müssen die Empfängerlisten zu erstellen und dann auszuliefern..

Code:
socket.on('connection', function(socket) // run server
{
    var deliver = function(from, to, data) // diese funktion ist ein wrapper und händelt das senden an bestimmte Zielgruppen oder an einzelne personen - jedoch nicht an zuvor ausgewählte Kontakte
    {
        if( is_int(lobby.sid[from]) ) // wenn from die socket.id enthält wird man unter lobby.sid die webseiten.uid (integer) erhalten, somit wird in Namen eines Users etwas gesendet.
        {
            from = {id: lobby.sid[from], name: lobby.clients[lobby.sid[from]]['name'] };
            switch( to )
            {
                // die Funktion welche deliver() callt muss definieren wohin die Daten geschickt werden
                case 'contacts':
                    var recipients = lobby.clients[from.id]['contacts']; // erhalte alle Kontakte des Users (online & offline-User)
                    break;
                case 'abo':
                    var recipients = lobby.clients[from.id]['aboCon']; // erhalte komplette liste der user die ein Abo zum User haben (online & offline-User)
                    break;
                default: // call to defined user
                    var recipients = {0: {id: to}};
                    break;
            }
            
            // nun Sender und Empfänger Daten wurden zusammengetragen, jetzt beginne die Auslieferung an diejenen die online sind
            for( var i in recipients )
            {
                var uID = recipients[i]['id'];
                if( lobby.isOn(uID) )
                {
                    var command = Object.keys(data)[0];
                    io.of('/root').connected[lobby.clients[uID]['sid']].emit(command, data[command]); // lobby.clients[uID]['sid'] liefert die socket.id welche unter der user.id (Webseite) gespeichert ist
                }
            }
        }
        else // from enthält keine socket.id sondern die id (type string) eines Eltern-Objekts das Abonniert werden kann - so wird hier an alle Abonnenten eines Objekts gesendet
        {
            // Durchsuche die User die Online sind und senden
            for( var uID in lobby.clients)
            {
                if( typeof lobby.clients[uID]['aboPro'] != 'undefined' && typeof lobby.clients[uID]['aboPro'][from] != 'undefined' ) // user ist online und aboniert diese Seite
                {
                    var command = Object.keys(data)[0];
                    io.of('/root').connected[lobby.clients[uID]['sid']].emit(command, data[command]);
                }
            }
        }
    }
    
    var deliverTo = function(from, to, data) // diese funktion wird nur an zuvor ausgewählten Kontakten etwas senden (nur die wo online sind)
    {
        // folgt...
    }
    
    socket.on('auth', function(sessID) // auth erfolgt via memcache über die abzurufende session
    {
        cache.get('socketSess/'+decodeURIComponent(sessID), function(error, result)
		{
			if( typeof(error)==="undefined" ) // ist ein memcache error aufgetretten erfolgt kein user.add
			{
				if( typeof(result) !== "undefined" && result != null ) // kein error nun prüfe die erhaltenen Daten
				{
					lobby.addClient( result, socket.id, sessID ); // sende json string und sid + sessID an die addClient funktion
				}
				else // erhaltene session war fehlerhaft/nicht vorhanden, erstelle eine neue und nutzte dann diese
				{
				    console.log('Client not added, no PHP-session found!');
				    socket.emit('reAuth');
				}
			}else{ 
				console.log("error : "+error);
			}
		});
	});
	
	socket.on('disconnect', function(){ lobby.remClient( socket.id ); }); // entferne Client aus der Instanz beim verlassen der Seite
	
	socket.on('getContacts', function(){
		var contactList = lobby.getData(socket.id, 'contacts');
		for (i = 0; i < contactList.length; ++i)
		{
			contactList[i]['online'] = ( lobby.isOn(contactList[i]['id']) ) ? 'on' : 'off';
		}
		deliver(socket.id, '', {'getContactDatas': contactList}); // nur zum testen & klappt alles =)
// 		socket.emit('getContactDatas', contactList);
	});
});
 
Zuletzt bearbeitet:
naja unklar nicht, aber würde von Jemanden der da schon Erfahrung hat gern wissen ob meine Lösung gut ist =)
Inzwischen hat sich zwar schon wieder bissl was geändert aber vom Prinzip eher nicht. Desshalb noch mal alles im Überblick:

Standard Server:
Code:
var server = require('http').createServer();
var io = require('socket.io').listen('7979'),
    mysql = require("mysql"),
    squel = require("squel"),
    memcache = require("memcache"),
	striptags = require('striptags');
	
// memcache Verbindung herstellen
var cache = new memcache.Client(11211, "localhost");
cache.connect();

// Create a Socket.IO instance, passing it our server
var socket = io.listen(server);
socket = socket.of('/global'); // set namespace

// db connection
var db = new mysql.createConnection({
//  ...
});
db.connect(function(err){
  if(err){
    console.log('Error connecting to Db');
	console.log(err);
    return;
  }
  else{ console.log('Connection established'); }
});

// lobby.clients.{uid}
var lobby = new function(){
	this.clients={}; // user instanzen werden hier in die user php-uid abgelegt welche auch als index genutzt wird
	this.sid={}; // hier gillt die socket.id als index und enthält jeweils die php-uid
	
	this.myID = function(socketID){ return this.sid[socketID]; }; // returned the userid from website
	this.isOn = function(uid){ return ( typeof this.clients[uid] != 'undefined' ) ? true : false }; // put website user id and check is current online
	
	this.addClient = function(data, socketID, sessID)
	{
		var userData = JSON.parse(data);
		if( userData.sid != '' ) // check of exist socket-id - user is listed 'update' this user
		{
			// JS-Instanz vorbereiten
			delete this.sid[userData['sid']]; // rem old socket.id from sid list
			this.sid[socketID] = parseInt(userData.uid); // set new socket.id and add the owner
			// Daten preparieren
			userData['sid'] = socketID; // neue socketID in php-sess speichern
			userData['sessKey'] = sessID; // muss für die js-Instanz wieder hinzugefügt werden
			userData['lastAct'] = new Date().toString(); // muss für die js-Instanz wieder hinzugefügt werden
			this.clients[userData['uid']] = userData; // session in instanz speichern
		}
		else // der user hat noch keine sid, er ist also das erste mal in der session mit socket verbunden
		{
			userData['sid'] = socketID;
			userData['sessKey'] = sessID;
			userData['lastAct'] = new Date().toString();
			this.clients[userData['uid']] = userData;
			this.sid[socketID] = parseInt(userData['uid']);
		}
		
		// php-sess updaten, nach jedem lobby.addClient
		delete userData['sessKey']; // will not need on php-sess
		delete userData['lastAct']; // will not need on php-sess
		cache.set('socketSess/'+sessID, JSON.stringify(userData), function(err, response) { /** Schreibvorgang kann hier geprüft werden */ });
		console.log('Client ('+socketID+') with u-ID ('+userData['uid']+') has connected');
	}
	
	this.disconnect = function(socketID)
	{
		var uid = this.myID(socketID);
		console.log('Add user: '+socketID+' ('+uid+') to disconnect loop');
		setTimeout(function()
		{
			// prüfe ob der user unter der selben uid noch existiert und ob er eine neue socket.id hat, wenn ja ist er bereits neu verbunden
			// also wurde ein reConnect ausgeführt und der user muss nicht entfernt werden
			if( typeof lobby.clients[uid] != 'undefined' && lobby.clients[uid]['sid'] != socketID )
			{
				// prüfe ob die alte socket.id noch der uid zugewiesen ist dann löschen...
				if(typeof lobby.sid[socketID] != 'undefined' && lobby.sid[socketID] == uid)
				{
					delete lobby.sid[socketID]; // remove unused sid
				}
				console.log('User: '+socketID+' ('+uid+') has reconnected');
			}
			else //  has leaved the Server
			{
				delete lobby.clients[uid]; // remove client
				// prüfe ob die alte socket.id noch der uid zugewiesen ist dann löschen...
				if(typeof lobby.sid[socketID] != 'undefined' && lobby.sid[socketID] == uid)
				{
					delete lobby.sid[socketID]; // remove sid
				}
				console.log('Lobby removed client: '+socketID+' ('+uid+')');
			}
		}, 5000, socketID, uid);
	}
	
	this.getData = function(sID, key) // socket ID
	{
		if( typeof this.sid[sID] != 'undefined' )
		{
			var uID = this.sid[sID];
			if( typeof this.clients[uID][key] != 'undefined' ){ return this.clients[uID][key]; }
		}
		else{ return false; }
	}
	
	this.addToGchat = function(userData)
	{
		// hier kommt später das zeug den user in einen gruppen chat hinzuzufügen
	}
};

socket.on('connection', function(socket) // run server
{
    var deliver = function(from, to, data) // diese funktion ist ein wrapper und händelt das senden an bestimmte Zielgruppen oder an einzelne personen - jedoch nicht an zuvor ausgewählte Kontakten
    {
        if( is_int(lobby.sid[from]) ) // wenn from die socket.id enthält wird man unter lobby.sid die webseiten.uid (integer) erhalten, somit wird in Namen eines Users etwas gesendet.
        {
            from = {id: lobby.sid[from], name: lobby.clients[lobby.sid[from]]['name'] };
            switch( to )
            {
                // die Funktion welche deliver() callt muss definieren wohin die Daten geschickt werden
                case 'contacts':
                    var recipients = lobby.clients[from.id]['contacts']; // erhalte alle Kontakte des Users (online & offline-User)
                    break;
                case 'abo':
                    var recipients = lobby.clients[from.id]['aboCon']; // erhalte komplette liste der user die ein Abo zum User haben (online & offline-User)
                    break;
                default: // call to defined user
                    var recipients = {0: {id: to}};
                    break;
            }
            
            // nun Sender und Empfänger Daten wurden zusammengetragen, jetzt beginne die Auslieferung an diejenen die online sind
            for( var i in recipients )
            {
                var uID = recipients[i]['id'];
                if( lobby.isOn(uID) )
                {
                    var command = Object.keys(data)[0];
                    io.of('/global').connected[lobby.clients[uID]['sid']].emit(command, data[command]); // lobby.clients[uID]['sid'] liefert die socket.id welche unter der user.id (Webseite) gespeichert ist
                }
            }
        }
        else // from enthält keine socket.id sondern die id (type string) eines Eltern-Objekts das Abonniert werden kann - so wird hier an alle Abonnenten eines Objekts gesendet
        {
            // Durchsuche die User die Online sind und sende
            for( var uID in lobby.clients)
            {
                if( typeof lobby.clients[uID]['aboPro'] != 'undefined' && typeof lobby.clients[uID]['aboPro'][from] != 'undefined' ) // user ist online und aboniert diese Seite
                {
                    var command = Object.keys(data)[0];
                    io.of('/global').connected[lobby.clients[uID]['sid']].emit(command, data[command]);
                }
            }
        }
    }
    
    var deliverTo = function(from, to, data) // diese funktion wird nur an zuvor ausgewählte Kontakten etwas senden (nur die wo online sind)
    {
        // folgt...
    }
    
	socket.on('disconnect',function(){ lobby.disconnect(socket.id); });
    socket.on('auth', function(data){
        switch( data.e )
        {
            case 'connect': // and reconnect
                cache.get('socketSess/'+decodeURIComponent(data.sessID), function(error, result) // auth erfolgt via memcache über die abzurufende session
                {
                    if( typeof(error)==="undefined" ) // ist ein memcache error aufgetretten erfolgt kein user.add
                    {
                        if( typeof(result) !== "undefined" && result != null ) // kein error nun prüfe die erhaltenen Daten
                        {
                            lobby.addClient( result, socket.id, data.sessID ); // sende json string und sid + sessID an die addClient funktion
                            socket.emit('finish');
                        }
                        else // erhaltene session war fehlerhaft/nicht vorhanden, erstelle eine neue und nutzte dann diese
                        {
                            console.log('PHP-session not found, run reAuth for: '+socket.id);
                            socket.emit('reAuth');
                        }
                    }else{ 
                        console.log("error : "+error);
                    }
                });
                break;
            case 'reconnect':
				console.log('reconnect');
                break;
            case 'disconnect':
                //lobby.remClient( socket.id ); // entferne Client aus der Instanz beim verlassen der Seite
				console.log( 'auth e.discconecct: '+socket.id+' leave the Server!' );
							//console.log( lobby.clients );
                break;
        }
	});
	
    socket.on('contact', function(data){
        switch(data.e)
        {
            case 'getList':
                var contactList = lobby.getData(socket.id, 'contacts');
                for (i = 0; i < contactList.length; ++i)
                {
                    contactList[i]['online'] = ( lobby.isOn(contactList[i]['id']) ) ? 'on' : 'off';
                }
                socket.emit('contact', {e: 'getListe', liste: contactList});
                break;
            case 'add':
                
                break;
            case 'remove':
                
                break;
            case 'block':
                
                break;
            case 'reject':
                deliver(socket.id, 8, {'testReceive': 'Bla'});
                break;
            case 'rejectBlock':
                
                break;
        }
	});
});
console.log('Juhu Server running');

Client:
Code:
socket.on('connect',function() {
    $.blockUI({ message: '<h1><img src="'+gfwSettings['IMG_URI']+'items/busy.gif" /> '+txt.get('dashboard', 'block_msg_connect')+'...</h1>' });
    socket.emit('auth', {e: 'connect', sessID: getCookie('WPOCMS')} );
});
socket.on('reAuth',function() {
    $.post('/'+BASE_URI+'ajax.php',{ tf: 'app/plugins/auth/checkInputs.php', process: "reAuth" }, function(data)
    {
        if( data )
        {
            socket.emit('auth', {e: 'connect', sessID: getCookie('WPOCMS')} );
        }
        else // sess is over redirect...
        {
            location.reload();
        }
    }, "html");
});
socket.on('finish',function() { $.unblockUI(); });

socket.on('contact',function(data)
{
    switch( data.e )
    {
        case 'getListe':
            updateContactlist( data.liste ); // func on dashboard.js
            break;
        case 'add':
            
            break;
        case 'rem':
            
            break;
    }
});

socket.on('testReceive', function(msg) { console.log(msg); });
 
Zuletzt bearbeitet:
Zurück
Oben