# Messengerstatus in Messenger integrieren



## Curry (12. Juli 2011)

Hallo liebe PCGH Community,

ich bin zur Zeit dabei einen Messenger zu programmieren in .net

Wie bei anderen Messengern wie z.B. ICQ meldet man sich Datenbankbasiert an. Diese ist abgesichert, z.B dass man nach 5 falschen Logins gesperrt wird usw.

Eine Kontaktliste ist nicht das Problem. Dieses habe ich folgendermaßen realisiert:

Datenbankname=Benutzer
-Freunde: {AUFLISTUNG} seiner Freunde mit Timestamp fürs adden usw.


Nun zum eigentlichen Problem:
Ich habe bloss das Problem, dass ich einen onlinestatus für jeden Benutzer haben möchte. 

Wie schaffe ich dieses zu realisieren, OHNE einen riesigen Datentraffic zu erzeugen?

Ich hatte erst überlegt das mit einem Boolwert in der Datenbank zu realisieren, jedoch schließen manche Anwender einfach den Messenger und somit wird der Datenbankwert nicht geändert.

Mit der Pingmethode lässt sich dieses Vorhaben auch nicht realisieren, da viele Router dieses blocken. Außerdem können Benutzer off sein, aucgh wenn ihr PC läuft udn ich somit eine Ping-Request erhalte. 


Habt ich vllt Ideen?
Benötigt ihr weitere Informationen? 

Wie machen das die großen Messenger wie MSN,Skype oder ICQ?


MfG

Curry


----------



## bingo88 (12. Juli 2011)

Nutzt du eine Client-Server-Architektur oder verbinden die User sich direkt zur DB?

Im Falle von ersteren:
a) im Server den Onlinestatus speichern (Liste aller User, die Online sind)
b) der Socket-Disconnect kann erkannt werden und der Status in der DB geändert werden
c) Diese Art von Ping wird meistens nicht über "Ping" (also ICMP Packete) gemacht, sondern über das Netzwerkprotokoll der Anwendung

Sind jetzt so drei dinge, die mir spontan eingefallen sind ^^


----------



## hardware_fanatiker (12. Juli 2011)

Also ich kenn mich jetzt mit .net nicht so aus, aber gibt es nicht nen destruktor für das gesamte programm, dann könnteste ja damit den boolean auf false setzen. Ansonsten ist doch der traffic garnicht so groß wenn der client jede minute nur kurz den server anpingt oder so.

Edit: Zu langsam.


----------



## Curry (12. Juli 2011)

@bingo88 Ich habe bisher das Login gemacht. Und dabei verbindet sich das PRogramm zu einem SQL Server. Bin noch nicht ganz so helle in C#. Vllt könntet ihr mir bisschen helfen, wie ich das am besten realisiere


----------



## bingo88 (12. Juli 2011)

Normalerweise besitzt so ein Chat einen separaten Server, der die Logik (Benutzerverwaltung etc.) übernimmt (es gibt auch peer-2-peer Netze, da sieht das anders aus). Im klassischen Client-Server modell sähe das so aus:

DB-Server <- SQL etc. -> dein Server <- dein Netzwerkprotokoll -> dein Client


----------



## Curry (12. Juli 2011)

Könnte ich jemand dafür begeistern da mal rein zuschauen?

Ich stehe da ein bisschen aufm Schlauch


----------



## Curry (13. Juli 2011)

Ich denke ich werde das mit einem Server machen. 
Gibt es eine Möglichkeit dem Server einen befehl zuschicken?

z.B. Send (EmpfängerIP, Nachricht) oder so?


----------



## Fragile Heart (13. Juli 2011)

Haha, ich arbeite gerade an was ähnlichen ... Zufälle gibst! 

Wie weit bist du denn? Hast du dir denn schon gedanken gemacht wie die Kommunikation genau laufen soll?


----------



## bingo88 (13. Juli 2011)

Ja wenn du keine bestehende Bibliothek nutzt, musst du das selbst implementieren (sprich: eigenes Protokoll entwerfen und implementieren).


----------



## Curry (13. Juli 2011)

Ich hatte mir das folgendermaßen vorgestellt:

User anschreiben:


Message inkl. UserID an Server senden
Server fragt IP anhand der UserID ab (UserID=Ähnlich ICQ Nummer/In DB vorhaden)
Baut Netzwerkstream zum Nutzer auf
Sendet Nachricht via TCPClient
Ist warscheinlich total affig, aber das ist dsa, was ich so bisher kann.

Mein Derzeitiges Problem: 
befehle an den Server zu senden.
bsp:
Sende (Nachricht, Userid)

[Also die Trennung von Befehl (Sende) und der Nachricht]

Bin für bessere Vorschläge immer gerne zu haben.


----------



## Fragile Heart (13. Juli 2011)

Wenn ich das richtig verstehe läuft alle Kommunikation über den Server oder? Damit könntest du, je nachdem wie das Programm nachher eingesetzt werden soll, schon mal recht viele Resourcen für ein privates Projekt binden. Aber das nur mal am Rande.  

Wenn du die Serversoftware selber machst, was du eh machen musst wenn du kein vorgefertigtes Protokoll verwenden willst, dann ist das Senden von Nachrichten doch eine Recht einfache Sache.


Nachricht im Client schreiben.
Zieladresse (deine UserID) mit der Nachricht an den Server senden. (du musst ja eh ein Protokoll definieren, dazu gehört dann halt auch das senden und empfangen)
Der Server kann die Absendeadresse ja durch die geöffnete Verbindung bestimmen.
Schauen ob eine aktive Verbindung zum Ziel besteht und senden (ansonsten speichern?)
Empfang der Nachricht am besten den Server bestätigen lassen
Bestättigung an an den sendenen Client weiter geben.


----------



## Curry (13. Juli 2011)

Wie wir gerde geschrieben haben, versuche ich das gerade auch.

Jedoch frage ich mich, wie ich soein Protokoll entwickeln soll.


----------



## bingo88 (14. Juli 2011)

Du musst dir überlegen, was du alles brauchst (also welche Nachrichten, z. B. Chat-Nachricht) und wie die einzelnen Nachrichten aufgebaut sein sollen.

Nehmen wir mal eine einfache Message-Nachricht an. Benötigte Daten:
- Sender
- Empfänger
- Nachrichteninhalt

Das müsstest du dann in eine geeignete Datenstruktur verpacken, die du dann über das Netzwerk versenden kannst. Dabei musst du dich fragen, ob du ein Binär- oder Textprotokoll (z. B. XML) nutzen willst. Der leichteste Teil ist eigentlich das Versenden und Empfangen von Paketen, die Schwierigkeit liegt eher in der Programmlogik (Behandeln von Nachrichten, Session-Management, etc.). Soetwas sauber und gut zu entwickeln ist nicht trivial und für den Einstieg ein sicherlich sehr frustrierendes Projekt.


----------



## Curry (14. Juli 2011)

Genau da liegt mein PRoblem.

Ich kann dem Server natürlich massenhaft Daten/Pakete schicken, aber der Server muss eben wissen, was damit machen soll..

An diesem PRobleme bin ich eben gerade.

Hat da jemand einen Plan/Tipps?


----------



## bingo88 (14. Juli 2011)

Dieser Kram erfordert normalerweise einiges an Entwurfsarbeit, das kann ich dir nicht abnehmen, da nur du weißt, was dein Programm alles können soll. Ich versuch es mal mit einem kleinen Beispiel (Textnachricht senden):

+ Client A sendet Nachricht an Client b:
->Nachricht: typ=Textnachricht sender=A empfänger=B text="Hallo, B!"

+ Server empfängt Nachricht von Client A:
->Nachrichtentyp abfragen => Textnachricht
->Empfänger ermitteln => B
->B in der Liste der verbundenen Clients suchen (nennen wir das jetzt mal die "Session" von B)
->Falls gefunden: Sende Nachricht an Client B, ansonsten sende Fehlermeldung an A oder was auch immer

+ Client B emfängt Nachricht von Client A
->Nachricht anzeigen

Das steckt teilweise mehr Aufwand hinter, als auf dem ersten Blick vielleicht zu sehen ist. Groß Fehlerprüfen ist hier natürlich auch noch nicht enthalten (z. B. darf A überhaupt senden und B empfangen?).


----------



## Curry (16. Juli 2011)

Hier meine Methode zum Senden:

static void Senden(string Nachricht)
        {
            Byte[] myByte;
            TcpClient myClient = new TcpClient("127.0.0.1", 21);
            NetworkStream Verbindung = myClient.GetStream();
            Verbindung.Write(myByte, 0, myByte.Length);
            Console.ReadLine();
        }


Und zum Empfangen:

TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
NetworkStream stream = client.GetStream();
int i;
    while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
                        Console.WriteLine("Received: {0}", data);


------------------------------------------------------------

Also von Client zu Client habe ich das hinbekommen.

Jetzt stellt sich die Frage wie ich das ganze über einen Server realisiere, der die BEfehle inkl. der Daten(Empfänger,Sender,Text...) auseinanderhalten kann


----------



## Curry (19. Juli 2011)

Push!


----------



## bingo88 (20. Juli 2011)

Du könntest zum Beispiel ein threadbasiertes Modell nehmen. Dabei wird für jede eingehende Connection am Server ein eigener Thread gestartet, der auf Nachrichten wartet (und diese behandelt). Du kannst dann zu dieser Verbindung noch zusätzliche Informationen speichern (bzw. du musst), z. B. ob zu dieser Verbindung ein User gehört und wenn ja, welchen Namen er hat. Alle Verbindungen musst du dann noch irgendwo speichern, möglichst mit einfacher Identifizierbarkeit. Wenn z. B. User A ne Nachricht an User B schicken will, musst du ja auch irgendwie wissen, wo die hin soll (sprich: welche Verbindung dafür verantwortlich ist). Du hast dir da nicht grade ne einfache Sache für den Einstieg ausgedacht


----------



## Curry (21. Juli 2011)

Genauso habe ich es vor^^

Das Grundgerüst ist soweit auch fertig.

Ich übergebe die Befehle an den Server in einem Byte

Hierzu setze ich feste BEfehlsketten mit Werten zusammen. 
BSP: 
Byte="Send12345678998765432100Hallo"
Pos 0-3=> Befehl="Send"
Pos 4-13=>Absender="123456789"
Pos 13-22=>Emfänger="987654321"
Pos 23,24=> Variablen (z.B Falls eine Dateiübertragung läuft"
Pos 25-Ende=>Nachricht="Hallo"

Ich will die Werte der Positionen in einem XML Dokument ablegen udn auslesen.

Die ganzen Internettutorials helfe mir dabei sehr wenig.

XML
_
<Commands>
       <Send>
           <cmdlang>4</cmdlang>
                <Absender>9</Absender>
               <Emfänger>9</Emfänger>
               <Variablen>2</Variablen>
       </Send>

_ _       <Recv>
                <cmdlang>6/cmdlang>
                <Absender>9</Absender>         
                <Emfänger>9</Emfänger>
               <Variablen>5</Variablen>
      </Recv>

</Commands>_

Wie kann ich genau DEN Wert auslesen, den ich genau suche.
Anwendungsbeispiel:

Ich baue einen String auf zum Versenden einer Textnachricht. Der Empänger(Server) bekommt die und möchte wissen, welche Substrings er sich herausschneiden muss.
Dazu soll er im XML Dokument nach "Recv" suchen. Und dann
int cmdlang= *HIER SOLL DIE ABFRAGE DES TAGS HIN,WElCHES UNTER "Recv" STEHT*


----------



## bingo88 (21. Juli 2011)

Wenn du es schon mit XML machen willst, kannst du auch direkt XML-Dokumente verschicken & parsen...

Bleiben wir mal bei einem einfachen Texprotokoll und betrachten beispielsweise "SEND":
SEND 12345 12346 Hallo, Welt!

=> Aufbau: <Nachrichtentyp><Trennzeichen><Sender-ID><Trennzeichen><Empfänger-ID><Trennzeichen><Nachricht>

Dein Protokoll legt fest, welcher Nachrichtentyp welche Struktur hat. Bspw. hat SEND die obige Struktur. Das heißt wenn der Server ein SEND empfängt weiß er, dass es insgesamt 4 Felder gibt, die jeweils durch ein eindeutiges Trennzeichen getrennt sind. Das erste Feld stellt den Nachrichtentyp dar, das zweite die ID-Nummer des Senders, das dritte die ID-Nummer des Empfängers und das letzte Feld die eigentliche Nachricht (da können Trennzeichen dann auch ignoriert werden, im Falle von Leerzeichen z. B.).

Alternativ könnte man auch die Länge der einzelnen Felder mitschicken, das erspart Probleme falls das Trennzeichen im Text vorkommen kann:
SEND|5|12345|5|12346|12|Hallo, Welt!
Die |-Striche habe ich jetzt nur zum verdeutlichen eingetragen, die gehören da sosnt nicht rein!


----------



## Curry (21. Juli 2011)

@Bingo88
Genauso habe ich das auch vor.

Ich erspare mir jedoch die Trennzeichen, da es sonst zu Problemen kommen kann.
Die Daten werden hinter eh mit genauer Position aus dem Byte geschnitten, deswegen kann ich sparsam mit Trennzeichen sein..
Mir fehlt eigentlich nurnoch das Codeschnippsel, wie ich die richtige Zeile aus dem XML auslesen kann.

Ich drücke das mal wie in SQL aus xD

Select cmdlang (also die Länge für den befehl aus dem Byte)
from XML-File
Where Element=Send


Das Tag <cmdlang> kommt öfters in der XML vor, jedoch will ich immer nur die länge haben, die ich für den aktuellen Befehl auch benötige.

Ich habe schon mit XMLReader / xPath gearbeitet, komme jedoch zu keinem brauchbaren Ergebnis.

Vielleicht kann sich jemand für die paar Zeilen erbarmen 

MfG

Curry


----------



## bingo88 (21. Juli 2011)

Ich verstehe jetzt ehrlich gesagt nicht, was du mit ner XML-*Datei* willst. Datei heißt ja, die Angaben kommen nicht über das Netz, sondern sind "fix". Da kannst du dann auch direkt mit fixen Positionsangaben arbeiten. Abgesehen davon bekommst damit Probleme, sobald Felder eine dynamische Länge besitzen können.

Solltest du ein XML-*Dokument* (bzw. Stream) meinen, der direkt über's Netzwerk geht, verstehe ich es allerdings auch nicht. Dann könntest du die Nachrichten ja direkt per XML versenden & verarbeiten und kannst dir dieses Indexgefummel sparen.


----------



## Curry (21. Juli 2011)

Ich will aus der XML Datei die Positionen für die Aufteilungs des Strings auslesen.


----------



## bingo88 (21. Juli 2011)

Ja das ist mir schon klar. Ist das eine echte Datei? Weil dann bekommst du Probleme:

SEND|User1|User2|Hallo!
Länge: 4, 5, 5, 6

SEND|User111|User2|Oops 
Länge: 4, 7, 5, 7
=>Hier hat sich die Länge eines Felds verändert! Wenn die Positionen jetzt fix in einer Datei stehen, wirst du nicht mehr die richtigen Felder auslesen.


----------



## Curry (21. Juli 2011)

@bingo88 

Alle Benutzer haben eine x Stellige ID. Diese ID wird übermittelt.

Bsp: ICQ Nummer (9 Stellig)


----------



## bingo88 (21. Juli 2011)

Ja dann mach das doch fest 
Sprich: Es wird eine SEND Nachricht erhalten -> Programm kennt den Aufbau, da eine SEND Nachricht nur so und nicht anders aufgebaut sein muss. Da macht man nichts mit externen Dateien die irgendwelche (gleichbleibenden) Felder angeben. Was das Performance kosten würde...

SEND|123456789|123456780|Text
Programm: SEND erhalten? Ja! => Sender = 9, Empfänger = 9, Rest = Nachricht. Alles andere wäre ein Formatfehler.


----------



## Curry (21. Juli 2011)

Ich will diese Werte aber nicht hardcoden, sondern kurz aus einem XML File auslesen


----------



## bingo88 (21. Juli 2011)

Der Sinn eines Protokolls ist es, zu beschreiben, wie Anwendungen untereinander kommunizieren. Wenn das einmal festgelegt ist, ist das festgelegt. Da ändert sich also nichts mehr dran. Aber gut, es ist halt deine Entscheidung und wenn du das so umständlich machen willst, will ich dich nicht davon abhalten 

Gut, also XML. Ich würde so spontan mal versuchen, das in ein XMLDocument zu parsen. Ich meine mich zu erinnern, da konnte man dann nach Entities (z. B. "send") suchen. Da ich mit XML aber so gut wie nie was mache, kann ich dir dazu jetzt auch erst mal nichts genaueres sagen und nur auf die MSDN Doku verweisen


----------



## Curry (21. Juli 2011)

Die hilft nur begrenzt xD


----------



## bingo88 (21. Juli 2011)

Hmm... ich meine die Funktion hieß GetElementsByTagName oder so


----------



## Curry (22. Juli 2011)

Ich lasse das mit dem XML.

Ich arbeite jetzt das Protokoll durch.


----------



## Curry (21. August 2011)

Könnte mir jemand helfen, ich versuche dass der Server Threadbasiert die Clients abarbeitet.

Jedoch komme ich nicht mehr weiter.


----------

