Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Server disconnectet Client (https://www.delphipraxis.net/36718-server-disconnectet-client.html)

PierreB 24. Dez 2004 09:22


Server disconnectet Client
 
hallo dp,

wiedermal ein socket-problem:

diesmal möchte ich vom server aus einzelne Clienten disconnecten.
beim connecten eines clienten werden die clienten-daten in ein listbox geladen:

Code:
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
 ib : integer;
begin
Memo1.Lines.Add(timetostr(now)+' Neuer User betritt den Chat !');
edit10.text := 'User eingeloggt: ' + IntToStr(ServerSocket1.Socket.ActiveConnections);
listbox1.Clear;
for ib := 0 to Serversocket1.Socket.ActiveConnections - 1 do
listbox1.Items.Add(serversocket1.Socket.Connections[ib].RemoteHost + ' ' + serversocket1.Socket.Connections[ib].remoteaddress);
end;
nun möchte ich das man ein item der listbox anklickt, dann auf den 'disconnect' button geht und die
verbindung zu diesem clienten getrennt wird.

oder eigentlich würde mir auch schon 'normaler' Code (ohne listbox) helfen. ;)

bisher habe ich folgendes versucht:
Code:
procedure button1click;
begin
serversocket1.socket.connections[0].disconnect(1);
// oder das:
serversocket1.socket.connections[1].disconnect(1);
end;
beides funzt aber net !

die delphi hilfe konnte mir nicht helfen und aus google wurde ich auch net schlau ! :roll:

Frohe Weihnachten !

Muetze1 24. Dez 2004 21:50

Re: Server disconnectet Client
 
Moin!

1. Warum löscht bei einem einzelnen Connect eines neuen Clients gleich die Listbox? Warum fügst du nicht einfach den Client der Listbox hinten an?

2. Warum nutzt du nicht die AddObject() Methode von TStrings und fügst den ServerSocket1ClientConnect() übergebenen Socket einfach mit an den Eintrag mit an? Dieser ist immer eindeutig zu der Connection.

3. Mit dem Vorschlag aus 2. wird es beim ServerSocket1ClientDisconnect() einfacher, weil du dann in dem Objects[] Array nachschauen kannst nach dem Socket der sich verabschiedet hat und somit nur noch den einen Eintrag löschen musst bei der ListBox

4. Und mit dem Vorschlag aus 2. wird deine eigentliche Frage (disconnecten eines gewählten Clients) auch einfach lösbar: Den Socket wieder aus dem Objects[] Array der ListBox rausholen, zu einem TCustomWinSocket casten und einfach seine Methdoe Close() aufrufen. Fertig ist die Suppe...

MfG
Muetze1

PierreB 25. Dez 2004 20:23

Re: Server disconnectet Client
 
Hallo,


Zitat:

1. Warum löscht bei einem einzelnen Connect eines neuen Clients gleich die Listbox? Warum fügst du nicht einfach den Client der Listbox hinten an?
das hatte ich versucht hat aber net geklappt ! Also lösche ich immer das listbox und schreibe dann alle
aktiven connections wieder rein ! :roll: (Not macht wohl erfinderisch !)
Zitat:

2. Warum nutzt du nicht die AddObject() Methode von TStrings und fügst den ServerSocket1ClientConnect() übergebenen Socket einfach mit an den Eintrag mit an? Dieser ist immer eindeutig zu der Connection.
weil ich nicht wusste das sowas geht ! :mrgreen: kannst du mir das bitte genauer erklären ?
Zitat:

3. Mit dem Vorschlag aus 2. wird es beim ServerSocket1ClientDisconnect() einfacher, weil du dann in dem Objects[] Array nachschauen kannst nach dem Socket der sich verabschiedet hat und somit nur noch den einen Eintrag löschen musst bei der ListBox
das ist natürlich besser als meine methode ! ;)
Zitat:

4. Und mit dem Vorschlag aus 2. wird deine eigentliche Frage (disconnecten eines gewählten Clients) auch einfach lösbar: Den Socket wieder aus dem Objects[] Array der ListBox rausholen, zu einem TCustomWinSocket casten und einfach seine Methdoe Close() aufrufen. Fertig ist die Suppe...
wunderbar ! nur wie geht das ganze ?

Muetze1 25. Dez 2004 22:14

Re: Server disconnectet Client
 
Moin!

Zitat:

Zitat von Muetze1
1. Warum löscht bei einem einzelnen Connect eines neuen Clients gleich die Listbox? Warum fügst du nicht einfach den Client der Listbox hinten an?

2. Warum nutzt du nicht die AddObject() Methode von TStrings und fügst den ServerSocket1ClientConnect() übergebenen Socket einfach mit an den Eintrag mit an? Dieser ist immer eindeutig zu der Connection.

Delphi-Quellcode:
Procedure TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
Var
  lTemp : String;
Begin
  Memo1.Lines.Add(timetostr(now)+' Neuer User betritt den Chat !');
  edit10.text := 'User eingeloggt: ' + IntToStr(ServerSocket1.Socket.ActiveConnections);

    // die oben übergebene Instanz "Socket" ist der neu angelegte Socket der für diesen neuen Client
    // angelegt wurde bzw. dessen Connection verwaltet. Daher können wir von ihm direkt die benötigten
    // Informationen wie RemoteHost etc abfragen. Ich habe hier mal eine temporäre lokale Variable lTemp
    // angelegt für den String der in ListBox erscheint.
    // Beim AddObject() kannst du ein Object mit angeben was dann zu dem Eintrag mit verwaltet wird. Wenn
    // du also mit Delete einen Eintrag löscht, dann fliegt dieses gleich mit raus. Daher hast du immer
    // zu jedem Eintrag den Socket und kannst z.B. wenn der Nutzer einen Eintrag in der ListBox ausgewählt
    // hat auch direkt diesem Client was schicken - einfach aus ListBox1.Items.Objects[] das Objekt rausholen
    // und zu einem TCustomWinSocket typecasten.

  lTemp := Socket.RemoteHost + ' ' + Socket.RemoteAddress;
  ListBox1.Items.AddObject(lTemp, Socket);
End;
Zitat:

Zitat von Muetze1
3. Mit dem Vorschlag aus 2. wird es beim ServerSocket1ClientDisconnect() einfacher, weil du dann in dem Objects[] Array nachschauen kannst nach dem Socket der sich verabschiedet hat und somit nur noch den einen Eintrag löschen musst bei der ListBox

Delphi-Quellcode:
Procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
Var
  i : Integer;
Begin
    // Socket ist eindeutig, daher haben wir durch das Connect schon diesen Socket auch in der ListBox.
    // Also: ListBox1.Items.Objects[] durchgehen, schauen wo dieser übergebene Socket ist und dann den
    // Eintrag löschen. Fertig!

  Memo1.Lines.Add(timetostr(now)+' User verlässt den Chat !');
  edit10.text := 'User eingeloggt: ' + IntToStr(ServerSocket1.Socket.ActiveConnections-1); // noch ist ActiveConnections nicht aktuell!

  For i := 0 To ListBox1.Items.Count-1 Do
  Begin
    If ( ListBox1.Items.Objects[i] = Socket ) Then
    Begin
      ListBox1.Items.Delete(i);
      Break;
    End;
  End;
End;
Zitat:

Zitat von Muetze1
4. Und mit dem Vorschlag aus 2. wird deine eigentliche Frage (disconnecten eines gewählten Clients) auch einfach lösbar: Den Socket wieder aus dem Objects[] Array der ListBox rausholen, zu einem TCustomWinSocket casten und einfach seine Methdoe Close() aufrufen. Fertig ist die Suppe...

Ich gehe jetzt mal davon aus, das du den Client rausschmeissen willst, den der Benutzer in der ListBox ausgewählt hat.

Delphi-Quellcode:
Procedure TForm1.Button1Click(Sender: TObject);
Var
  lSocket : TCustomWinSocket;
Begin
    // wenn ein Eintrag ausgewählt ist...
  If ( ListBox1.ItemIndex > -1 ) Then
  Begin
      // dann den mit AddObject() hinzugefügten Socket mal rausholen
    lSocket := ListBox1.Items.Objects[ ListBox1.ItemIndex ] As TCustomWinSocket;

      // ... und dann einfach den Socket schliessen
    lSocket.Close;
  End;
End;
Voraussetzung für alle von mir hier dargelegten Posts ist es, dass MultiSelection ausgeschaltet ist bei der ListBox!

MfG
Muetze1

PierreB 25. Dez 2004 22:18

Re: Server disconnectet Client
 
Ich danke dir erstmal ;)

Ich teste das morgen mal aus !

PierreB 26. Dez 2004 12:43

Re: Server disconnectet Client
 
hallo muetze1,

vielen dank für deine hilfe funzt alles wunderbar ;)

warum bin ich da nicht selber drauf gekommen ? :mrgreen:

jetzt hab ich nur ( :roll: ) noch ein problem:

da alle clienten dann in der listbox abgespeichert werden, steht da ja der host und die ip.
wenn nun aber mehrere clienten eingeloggt sind, weiß ich dann nicht mehr welcher listbox-eintrag
(also ip + host) nun zu welchem user gehört !

deshalb habe ich versucht den nicknamen mit in die listbox zu speichern:
Im ClientConnect steht:
Code:
 ClientSocket1.Socket.SendText(xorstring(nachricht, ''));
Nachricht setzt sich aus dem Nicknamen (den der User eingibt) und 'hat den Raum betreten' zusammen.
Da der Nickname eh nur 6 Zeichen haben darf, hab ich ihn wie folgt ausgelesen:
Code:
procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
   Texta, encode : string;
begin
texta := Socket.ReceiveText;
nick := xorstring(texta, '');
nick:=Copy(nick, 1, 6);
showmessage(nick);
end;
nun hab ich zwar den nicknamen im serverprogramm, doch wie bekomm ich den nun zu dem entsprechenden
host + ip eintrag in die listbox ?? hab schon versucht das mit bei OnClientConnect einzubauen,
aber da ClientRead ja erst nach OnClientConnect ausgeführt wird, funzt das net !

Muetze1 26. Dez 2004 17:44

Re: Server disconnectet Client
 
Moin!

Richtig, beim ClientConnect gibt es noch keine Kommunikation und der Client kann daher nur danach seinen Nick schicken. Daher musst du das nachträglich zuordnen. Erstmal aber nochwas zwischendurch: Die ListBox speichert nicht die Sockets - sie hält auch einen Verweis auf diese Instanzen. Der ServerSocket verwaltet und hält diese hauptsächlich. Daher kannst du z.B. auch weiterhin die Connections[] des ServerSockets durchgehen um den Nickname zu zu ordnen. Andere Möglichkeit: Du baust dir ein Objekt - besser eine kleine Klasse - die nix weiter enthält als 2 Variablen im Public Bereich:

Delphi-Quellcode:
  TUserSocket = Class
  Public
    Socket : TCustomWinSocket;
    NickName : String;
  End;
Und wenn du nun bei der ListBox einfach anstatt dem Socket folgendes hinzufügst:

Delphi-Quellcode:
Procedure TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
Var
  lTemp : String;
  lUser : TUserSocket;
Begin
  Memo1.Lines.Add(timetostr(now)+' Neuer User betritt den Chat !');
  edit10.text := 'User eingeloggt: ' + IntToStr(ServerSocket1.Socket.ActiveConnections);

  lUser := TUserSocket.Create;
  lUser.Socket := Socket;
  lUser.NickName := ''; // noch unbekannt, sind ja im Connect...

  lTemp := Socket.RemoteHost + ' ' + Socket.RemoteAddress;
  ListBox1.Items.AddObject(lTemp, lUser);
End;
Somit haben wir es nun so, das wir nicht mehr direkt den Socket reinhängen sondern diese Instanz von TUserSocket die uns beide nötigen Informationen hält: Den Socket und den Nick. Nun fehlt noch die Zuordnung vom Nick:

Delphi-Quellcode:
  // Diese Funktion geht nur durch die ListBox durch und sucht den TUserSocket zu dem übergebenen Socket
Function TForm1.FindUserSocket(ASocket : TCustomWinSocket): TUserSocket;
Var
  i : Integer;
Begin
  Result := Nil;

  For i := 0 To ListBox1.Items.Count-1 Do
    If ( TUserSocket(ListBox1.Items.Objects[i]).Socket = ASocket ) Then
    Begin
      Result := TUserSocket(ListBox1.Items.Objects[i]);
      Break;
    End;
End;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  lUser : TUserSocket;
  lText : string;
begin
  lText := Socket.ReceiveText;

  lUser := FindUserSocket( Socket );
 
  If ( Assigned(lUser) ) Then
  Begin
    lText := xorstring(lText, '');
    lUser.NickName := Copy(lText, 1, 6);

    ShowMessage(lUser.NickName);
  End;
End;
Nun enthält die TUserSocket in der ListBox auch den Nickname, wenn der denn ankommt.

Dadurch, das in der ListBox nun eine Instanz von TUserObject hängt die wir selber instanziiert haben, müssen wir uns um die Freigabe kümmern und natürlich die anderen Routinen abhändern.

Delphi-Quellcode:
Procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
Var
  i : Integer;
  lUser : TUserSocket;
Begin
    // Socket ist eindeutig, daher haben wir durch das Connect schon diesen Socket auch in der ListBox.
    // Also: ListBox1.Items.Objects[] durchgehen, schauen wo dieser übergebene Socket ist und dann den
    // Eintrag löschen. Fertig!

  Memo1.Lines.Add(timetostr(now)+' User verlässt den Chat !');
  edit10.text := 'User eingeloggt: ' + IntToStr(ServerSocket1.Socket.ActiveConnections-1); // noch ist ActiveConnections nicht aktuell!

  lUser := FindUserSocket( Socket );

  If ( Assigned(lUser) ) Then
  Begin
    For i := 0 To ListBox1.Items.Count-1 Do
    Begin
      If ( ListBox1.Items.Objects[i] = lUser ) Then
      Begin
        ListBox1.Items.Delete(i);
        Break;
      End;
    End;

    lUser.Free;
  End;
End;

Procedure TForm1.Button1Click(Sender: TObject);
Var
  lUser : TUserSocket;
Begin
    // wenn ein Eintrag ausgewählt ist...
  If ( ListBox1.ItemIndex > -1 ) Then
  Begin
      // dann den mit AddObject() hinzugefügten TUserSocket mal rausholen
    lUser := ListBox1.Items.Objects[ ListBox1.ItemIndex ] As TUserSocket;

    ShowMessage(lUser.NickName + ' wurde gekickt');

      // ... und dann einfach den Socket schliessen
    lUser.Socket.Close;
  End;
End;
Zu den ClientSocket/ServerSocket als Chat mit Nicks, Channels, etc siehe für Ideen und Hinweise auch den (bisher noch unkommentierten) Code von mir an: Chat Beispiel.

MfG
Muetze1

PierreB 27. Dez 2004 12:22

Re: Server disconnectet Client
 
:gruebel:

Code:
TUserSocket = Class
bin ich blöd ? Das muss doch bei type rein, oder ?
da kommt fehlermeldung:
Zitat:

Typ TUserSocket ist nicht vollständig definiert.
:gruebel:

Pseudemys Nelsoni 27. Dez 2004 12:27

Re: Server disconnectet Client
 
das was du da hast ist eine vorwärtsdeklaration... du musst die klasse auch noch irgendwo "richtig" deklarieren (die abschnitte/methoden/felder der klasse etc)

Muetze1 27. Dez 2004 13:10

Re: Server disconnectet Client
 
Moin!

Zitat:

Zitat von delphman
:gruebel:

Code:
TUserSocket = Class
bin ich blöd ? Das muss doch bei type rein, oder ?
da kommt fehlermeldung:
Zitat:

Typ TUserSocket ist nicht vollständig definiert.
:gruebel:

Ich bin davon ausgegangen das dieses zu erkennen kein Problem wäre. Du hast es doch auch ordentlich erkannt, daher: warum dieser Post? Was anderes kanns nich sein, auch keine forward declaration, weil die Definition der Klasse direkt folgt...

Natürlich heisst es so
Delphi-Quellcode:
Type
  TUserSocket = Class
  Public
    Socket : TCustomWinSocket;
    NickName : String;
  End;
:wall: :wall: :wall:

MfG
Muetze1

PierreB 27. Dez 2004 13:14

Re: Server disconnectet Client
 
:wall:

oh, ich dachte das kommt in den allgemeinen public ! sorry !

:wall: :wall:

nochmal vielen dank für deine hilfe ! :wink:

wenn ich mein programm dann veröffentliche (natürlich in der dp) werde ich dich dankend erwähnen ;)

Muetze1 27. Dez 2004 13:15

Re: Server disconnectet Client
 
Moin!

Zitat:

Zitat von delphman
oh, ich dachte das kommt in den allgemeinen public ! sorry !

Was bedeutet für dich: "allgemeiner public"??

Zitat:

Zitat von delphman
wenn ich mein programm dann veröffentliche (natürlich in der dp) werde ich dich dankend erwähnen

Lass das mal lieber mit dem erwähnen von meinem nick...

MfG
Muetze1

PierreB 27. Dez 2004 13:20

Re: Server disconnectet Client
 
Zitat:

Was bedeutet für dich: "allgemeiner public"??
na gleich das unter dem type. was standardmäßig schon da steht !


Zitat:

Lass das mal lieber mit dem erwähnen von meinem nick..
wieso das?

Muetze1 27. Dez 2004 13:33

Re: Server disconnectet Client
 
Moin!

Zitat:

Zitat von delphman
Zitat:

Was bedeutet für dich: "allgemeiner public"??
na gleich das unter dem type. was standardmäßig schon da steht !

Ich kapier's nicht. Abhängig vom Interface bzw. Implementation Teil stehen dort entweder Funktions-, Konstanten- oder Variablendefinitionen, wobei im Implementation Teil natürlich Funktionsimplementationen kommen und keine Funktionsdefinitionen. Aber ich weiss nicht was da standardmässig stehen sollte oder meinst du ganz allgemein den Interface Abschnitt? Das bringt mich dann wieder durcheinander warum das "Type" vorhin in Bezug auf den "allgemeinen public" Bereich nicht so klar ist, vor allem da wir ja nun schon geklärt haben, das es der "allgemeine Public" Bereich anscheinend ja nicht war, wo das "Type" hinmusste...

MfG
Muetze1

PierreB 27. Dez 2004 13:38

Re: Server disconnectet Client
 
:gruebel:

wenn du bei delphi ein neues formular erstellst, steht in der "leeren" Unit bereits ein type !?

[ot]was nu mit deinem namen? wieso nicht ? [/ot]

PierreB 28. Dez 2004 12:45

Re: Server disconnectet Client
 
Hi,

ich hab mir deinen Source jetzt ma angeguckt, bin an der Umsetzung aber gescheitert.
Ich hab genau deinen Source genommen, hat aber nicht funktioniert, d.h. die ListBox blieb ganz
leer, weder IP noch Host wurde angezeigt.

Aus lauter Programmierfrust ( :wall: ) hab ich nochma drüber nachgedacht und bin auf folgendes
gekommen:
Code:
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
var
ltemp :string;
begin
edit10.text := 'User eingeloggt: ' + IntToStr(ServerSocket1.Socket.ActiveConnections);
nick := Socket.ReceiveText;
nick1 := xorstring(nick, '');
memo1.lines.Add(nick1);
nick1:=Copy(nick1, 1, 6);
lTemp := Socket.RemoteHost + ' ' + Socket.RemoteAddress + ' ' + nick1;
ListBox1.Items.AddObject(lTemp, Socket);
end;
Achso beim Clienten steht dann logischerweise:
Code:
procedure ClientSocket1ClientConnect;
begin
ClientSocket1.socket.sendtext(nachricht);
Das funktioniert aber nicht immer, nur manchmal, d.h. es macht was es will !!!!
Meistens geht es beim zweiten Mal, also wenn der Client die Verbindung trennt und
erneut herstellt dann geht es.

Wieso das ?

Muetze1 28. Dez 2004 13:58

Re: Server disconnectet Client
 
Moin!

Debuggen kann ich dazu nur sagen. Und wenn du den Fehler durch das debuggen nicht findest (jeder muss das mal lernen), dann kannst du uns den Quellcode hier hinten anhängen und mal nachfragen ob es sonst einer von uns tut. Bei dem oben geposteten Code sehe ich keinen grundlegenden Fehler, daher liegt es wahrscheinlich am Zusammenspiel.

MfG
Muetze1

PierreB 28. Dez 2004 14:05

Re: Server disconnectet Client
 
Ich glaube das hängt irgendwie damit zusammen, dass im OnClientRead der Server die Nachricht ja verarbeiten will, dies dann aber im ClientConnect ja schon getan wurde !
Kann das sein das die beiden sich da gegenseitig in die Quere kommen ?

Muetze1 28. Dez 2004 14:16

Re: Server disconnectet Client
 
Moin!

OnClientConnect:

Wir einmalig beim Verbindungsaufbau aufgerufen. Zu diesem Zeitpunkt wurde der Aufbau der Verbindung mit dem Client abgeschlossen und die Verbindung steht. Es liegen noch keine Daten an, die man empfangen könnte. Wenn man in diesem Ereignis ein ReceiveText o.ä. aufruft, dann ist es mehr als Zufall, wenn dort was zu empfangen wäre.

OnClientRead:

Dieses Ereignis kann mehrfach aufgerufen werden. Es wird immer ausgelöst, wenn Daten vom Client empfangen wurden und im Buffer abgelegt wurden. Diese können dann im OnClientRead ausgelesen werden. Mit dem Auslesen werden diese Daten auch gleich aus dem Buffer entfernt. Die zu empfangenen Daten können in unterschiedliche Teile zerstückelt sein, es gibt keine Garantie das sie in einem Stück bzw. genauso unterteilt ankommen wie sie losgeschickt wurden. Es kann also vorkommen das 2 nacheinander mit SendText losgeschickte Texte mit einem einzigen ReceiveText empfangen werden. Genausogut kann es mehrere OnClientRead und ReceiveText benötigen um einen Text zu empfangen der auf der Clientseite mit einem einzigen SendText verschickt wurde.

Ein Auslesen des Buffers durch ReceiveBuf() oder ReceiveText sollte immer nur im OnClientRead statt finden.

Nein, es kann nicht sein, das diese sich behackeln - wenn man beachtet das ein ReceiveBuf()/-Text() nur im OnClientRead stattfinden darf.

MfG
Muetze1

PierreB 28. Dez 2004 14:19

Re: Server disconnectet Client
 
Aber beim Client-Programm schick ich ja auch im ClientConnect eine Nachricht zum Server.
Die soll ja dann halt im Server auch bei ClientConnect eben lesen. Vielleicht gehts nur nicht weils zu schnell ist, d.h. vielleicht sollte man beim ClientConnect noch ein delay oder sowas einbauen ??

Muetze1 28. Dez 2004 14:28

Re: Server disconnectet Client
 
Moin!

Zitat:

Zitat von delphman
Aber beim Client-Programm schick ich ja auch im ClientConnect eine Nachricht zum Server.
Die soll ja dann halt im Server auch bei ClientConnect eben lesen.

Schicken kannst du Nachrichten wann du willst, Hauptsache der Socket existiert. Wenn du im OnClientConnect was sendest, dann kannst du es erst im OnClientRead auslesen - und dieses Event kommt immer nach dem OnClientConnect. Das du jetzt schon was im OnClientConnect auslesen kannst bei deinem Server liegt in der Tat daran das du es im lokalen LAN benutzt und es daher schnell ist. Der von dir gesendete String löst so oder so ein OnClientRead aus und daher ist es nicht gut im OnClientConnect des Servers zu versuchen den Text schon auszulesen.

Du musst dich von der Vorstellung trennen, beim Connect des Clients dessen NickName zu erfahren - das geht nur im nachhinein. Du musst dir in deinem Programm eine solche Struktur vorhalten, das du den Nicknamen er später erfährst - es geht nicht anders. In meinem oben verlinkten Chat wird das ganze zwar über Streams gelöst aber trotzdem wird dort der NickName auch erst später übermittelt. Trotzdem ist es noch schnell genug als das es nicht auffällt.

MfG
Muetze1

PierreB 28. Dez 2004 14:33

Re: Server disconnectet Client
 
Ok, du hast Recht ! :thumb:

Gibs nicht ne andere Möglichkeit den Nicknamen "einfach" mit in die ListBox zu bekommen, ohne eine extra Class zu erstellen ?

Wenn nicht dann lass ich dieses Feature halt weg ! ;)

Muetze1 28. Dez 2004 14:40

Re: Server disconnectet Client
 
Moin!

Zitat:

Zitat von delphman
Ok, du hast Recht ! :thumb:

Gibs nicht ne andere Möglichkeit den Nicknamen "einfach" mit in die ListBox zu bekommen, ohne eine extra Class zu erstellen ?

Wenn nicht dann lass ich dieses Feature halt weg ! ;)

Klar, wenn du im OnClientRead den NickName empfängst...

... dann hast du nämlich folgendes:

1. in der Procedure hast du den Socket übergeben bekommen
2. du hast den nick ausgelesen aus dem mit ReceiveText empfangenen
3. du hast die ListBox wo hinten bei Items.Objects[] der Socket drinne steht der dir übergeben wurde
4. Wenn du den Eintrag in 3. gefunden hast, dann kannst du doch einfach seinen Text abändern.

MfG
Muetze1

PierreB 28. Dez 2004 14:46

Re: Server disconnectet Client
 
Zitat:

Klar, wenn du im OnClientRead den NickName empfängst...

... dann hast du nämlich folgendes:

1. in der Procedure hast du den Socket übergeben bekommen
2. du hast den nick ausgelesen aus dem mit ReceiveText empfangenen
3. du hast die ListBox wo hinten bei Items.Objects[] der Socket drinne steht der dir übergeben wurde
4. Wenn du den Eintrag in 3. gefunden hast, dann kannst du doch einfach seinen Text abändern.
klar, wenn dann aber ein Client was schreibt wird ja jedesmal (!) der nick in die listbox geschrieben !

Wenn ein Client sich einloggt sendet dieser ja automatisch 'MrX hat Raum betreten'.
Nun müsste man doch eigentlich nur ein einziges Mal (für jeden Clienten) diese achricht abfangen und in die Listbox schreiben !?

Muetze1 28. Dez 2004 18:51

Re: Server disconnectet Client
 
Moin!

Zitat:

Zitat von delphman
klar, wenn dann aber ein Client was schreibt wird ja jedesmal (!) der nick in die listbox geschrieben !

Wenn ein Client sich einloggt sendet dieser ja automatisch 'MrX hat Raum betreten'.
Nun müsste man doch eigentlich nur ein einziges Mal (für jeden Clienten) diese achricht abfangen und in die Listbox schreiben !?

Ok, wenn der Client auch immer ständig seinen Nick mitschickt, obwohl der Server ihn ja schon weiss...

Aber dann lass uns doch mal überlegen. Wir müssten uns doch einfach eine Situation raussuchen die nur einmal auftritt und am besten kurz nach dem Verbinden. Also mir fällt da z.B. "Mrx hat den Raum betreten" ein - warum achtest/wartest du nicht auf den Spruch und holst dir da den Nick raus und fügst ihn zur Listbox hinzu - nochmal sollte der Spruch ja nicht kommen.

MfG
Muetze1

PierreB 28. Dez 2004 18:59

Re: Server disconnectet Client
 
Genau daran hab ich auch schon gedacht.
Vielleicht mit POS ? Aber dann müsste man das gesamte memo in einen string kopieren und wie krieg ich dann noch den nick raus selbst wenn ich 'hat den Raum betreten' gefunden habe ?

wie meinst du das, den nick rausholen ?

PierreB 28. Dez 2004 21:52

Re: Server disconnectet Client
 
Hi,

nach langem probieren habe ich es jetzt geschafft ! :party:
Sobald sich ein User einloggt, wird der Nick mit in der ListBox angezeigt !
Hier der Source:
Code:
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
wert, wert1, ib : integer;
begin
edit10.text := 'User eingeloggt: ' + IntToStr(ServerSocket1.Socket.ActiveConnections);
lTemp := Socket.RemoteHost + ' ' + Socket.RemoteAddress;
timer2.Enabled := true;
end;
Sobald sich ein User einloggt, geht der Timer "an". Und im Timer passiert folgendes:
Code:
procedure TForm1.Timer2Timer(Sender: TObject);
begin
if nick <>'' then begin
                  nick:=Copy(nick, 1, 6);
                  test := ltemp + ' ' + nick;
                  ListBox1.Items.AddObject(test, ServerSocket1);
                  timer2.Enabled := false;
                  end;
end;
Sobald ein Client etwas sendet wird die Nachricht abgefangen und das Item der ListBox zugefügt.

Nun gibt es wieder ein neues Problem:
Das User kicken funktioniert jetzt nicht mehr ! :wall:
Fehlermeldung: Ungültige Typumwandlung.

Dabei hat sich doch eigentlich nix verändert, außer der Wert der in die ListBox eingetragen wird ! :gruebel:

Echt schlimm: ein Problem gelöst, kommt ein neues ! :roll:

Muetze1 28. Dez 2004 22:41

Re: Server disconnectet Client
 
Moin!

Aua aua aua...

Deine Variable "nick" ist wohl global und daher fällt deine Methode schonmal flach, wenn sich 2 Nicks/clients direkt nacheinander anmelden, dann haut er die Nicks durcheinander bzw. nutzt den gleichen nick für beide.

Dann nochmal ein Zitat von dir:
Zitat:

Zitat von delphman
Dabei hat sich doch eigentlich nix verändert, außer der Wert der in die ListBox eingetragen wird !

. Wie bitte? Nix verändert? Schonmal geschaut was du nun in der ListBox hinten anhängst? Den ServerSocket. Hmm, warum nur ... frage ich mich. Den ServerSocket kann ich jederzeit und überall bekommen wenn ich ServerSocket1 schreibe - und der ist bei jedem User gleich - also, was soll der denn bei den Usern in der ListBox? Es hilft doch nix wenn überall das gleiche drinne steht. Und bisher ging ich in meinem Code immer davon aus das entweder TUserSocket oder TCustomWinSocket (abhängig welchen Stand man nimmt aus diesem Thread) in Items.Objects[] der ListBox befindet. Nun befindet sich durch dein Code aber TServerSocket drinne - und das ist doch wohl komplett was anderes. Nun ist denke ich mal auch klar, warum das Programm sagt:
Zitat:

Zitat von Das Programm
Ungültige Typumwandlung

, weil nunmal ein TServerSocket kein TCustomSocket und auch kein TCustomWinSocket ist.

Und warum überhaupt mit dem Timer? Warum? Warum bloss? Woher willst du wissen, das bis zum Ablauf des Timers der Nick angekommen ist? Und woher willst du wissen das es der Nick zu dem Socket ist? Du hast einen ServerSocket der haufenweise Clients haben kann.

Dein ganzes Programm sollte im Normalfall Event-driven sein, daher: reagiere auf Ereignisse und handle nicht selber.

Zitat:

Zitat von delphiman
Vielleicht mit POS ? Aber dann müsste man das gesamte memo in einen string kopieren und wie krieg ich dann noch den nick raus selbst wenn ich 'hat den Raum betreten' gefunden habe ?

Wieso das gesamte Memo??? Du bekommst den String doch beim OnClientRead. Diese String untersuchen ob es diese "betreten"-Meldung ist und danach so oder so zum Memo hinzufügen (den gesamten String). Wenn es diese "betreten"-Meldung ist, dann kannst du ja den Nick rausholen und der ListBox zuführen.

Funktionen dazu: Pos(), Copy(), Delete()

MfG
Muetze1

PierreB 28. Dez 2004 22:50

Re: Server disconnectet Client
 
Zitat:

weil nunmal ein TServerSocket kein TCustomSocket und auch kein TCustomWinSocket ist.
Das heißt ich änder das einfach zu TCustomSocket, ja ?
Zitat:

Und warum überhaupt mit dem Timer? Warum? Warum bloss?
Warum nicht ?
Zitat:

Woher willst du wissen, das bis zum Ablauf des Timers der Nick angekommen ist? Und woher willst du wissen das es der Nick zu dem Socket ist? Du hast einen ServerSocket der haufenweise Clients haben kann.
hä? Wenn ein User einloggt wird der Timer aktiviert. Dann prüft er die eingehende Nachricht. Der der Client gleich nach dem Verbinden ja Nickname + hat den Raum betreten sendet, fängt der Timer diese Nachricht ab. er löscht den Rest des Strings und packt den Nick in die ListBox. Danach wird der Timer wieder ausgeschaltet, bis wieder ein Client einloggt. Dann geht das ganze wieder von vorne los !

Zitat:

der ListBox zuführen.
wie füge ich den einem bereits existierenden Item noch etwas hinzu ?

Muetze1 28. Dez 2004 23:14

Re: Server disconnectet Client
 
Moin!

Zitat:

Zitat von delphman
Zitat:

weil nunmal ein TServerSocket kein TCustomSocket und auch kein TCustomWinSocket ist.
Das heißt ich änder das einfach zu TCustomSocket, ja ?

Meinst du wirklich, das ist so einfach? Wenn du es so haben willst wie bisher, dann füge die aktuelle Connections[] - also den Socket - hinzu.

Zitat:

Zitat von delphman
Zitat:

Und warum überhaupt mit dem Timer? Warum? Warum bloss?
Warum nicht ?
Zitat:

Woher willst du wissen, das bis zum Ablauf des Timers der Nick angekommen ist? Und woher willst du wissen das es der Nick zu dem Socket ist? Du hast einen ServerSocket der haufenweise Clients haben kann.
hä? Wenn ein User einloggt wird der Timer aktiviert. Dann prüft er die eingehende Nachricht. Der der Client gleich nach dem Verbinden ja Nickname + hat den Raum betreten sendet, fängt der Timer diese Nachricht ab. er löscht den Rest des Strings und packt den Nick in die ListBox. Danach wird der Timer wieder ausgeschaltet, bis wieder ein Client einloggt. Dann geht das ganze wieder von vorne los !

Ach, und was ist, wenn sich ein 2. Client einloggt bzw. verbindet während der erste den Timer angeschmissen hat, diese aber noch nciht ausgelöst hat? Was ist dann? Wem gehört der Nick? Aus welchem Socket willst du lesen?

Zitat:

Zitat von delphman
Zitat:

der ListBox zuführen.
wie füge ich den einem bereits existierenden Item noch etwas hinzu ?

Delphi-Quellcode:
ListBox1.Items[Index] := 'Was auch immer';
Index ist dabei der Index des Eintrages den du ändern möchtest.

MfG
Muetze1

PierreB 29. Dez 2004 20:14

Re: Server disconnectet Client
 
Zitat:

Meinst du wirklich, das ist so einfach? Wenn du es so haben willst wie bisher, dann füge die aktuelle Connections[] - also den Socket - hinzu.
hä ? den Sokcket hab ich doch schon hinzugefügt ! Mit ServerSocket :gruebel:

Zitat:

Ach, und was ist, wenn sich ein 2. Client einloggt bzw. verbindet während der erste den Timer angeschmissen hat, diese aber noch nciht ausgelöst hat? Was ist dann? Wem gehört der Nick? Aus welchem Socket willst du lesen?
Das ist mir eigentlich egal, die Wahrscheinlichkeit das so etwas eintritt sollte ziemlich gering sein, da ich eh nur mit paar Leuten chatten werde. Und den sag ich dann halt, der der erste um 18.30Uhr kommen soll, der zweite um 18.31Uhr, usw. ;)

Aber warum funktioniert denn das kicken jetzt nicht mehr ? :gruebel:

Muetze1 29. Dez 2004 23:27

Re: Server disconnectet Client
 
Moin!

Zitat:

Zitat von delphman
Zitat:

Meinst du wirklich, das ist so einfach? Wenn du es so haben willst wie bisher, dann füge die aktuelle Connections[] - also den Socket - hinzu.
hä ? den Sokcket hab ich doch schon hinzugefügt ! Mit ServerSocket :gruebel:

Zitat:

Ach, und was ist, wenn sich ein 2. Client einloggt bzw. verbindet während der erste den Timer angeschmissen hat, diese aber noch nciht ausgelöst hat? Was ist dann? Wem gehört der Nick? Aus welchem Socket willst du lesen?
Das ist mir eigentlich egal, die Wahrscheinlichkeit das so etwas eintritt sollte ziemlich gering sein, da ich eh nur mit paar Leuten chatten werde. Und den sag ich dann halt, der der erste um 18.30Uhr kommen soll, der zweite um 18.31Uhr, usw. ;)

Aber warum funktioniert denn das kicken jetzt nicht mehr ? :gruebel:

Ganz einfach: weil du nicht mehr den jeweiligen Socket der Verbindung der ListBox hinzufügst, sondern nur die TServerSocket Komponente an sich. Das ist aber die Komponente und diese enthält die einzelnen Sockets zu den Clients (u.a. durch die Connections[] Eigenschaft erreichbar). Und wenn dir nicht klar ist, das eine Klasse Namens TServerSocket was anderes ist als die Klasse TCustomWinSocket und diese auch nicht von einander abgeleitet sind um kompatibel zu sein, dann empfehle ich dir erstmal grundlegend das Klassentutorial von Luckie.

So hart es klingen mag, aber ich weiss sonst nicht gross wie ich dir das sonst verständlich machen soll...

MfG
Muetze1

PierreB 30. Dez 2004 10:15

Re: Server disconnectet Client
 
Moin,


ok, ich gucks mir nochmal an.

Trotzdem vielen Dank für deine Hilfe ! ;)

Muetze1 30. Dez 2004 17:34

Re: Server disconnectet Client
 
Moin!

Mir ist noch was eingefallen zur Verdeutlichung:

Angenommen wir haben mehrere Komponenten auf einer Form und immer wenn auf einer von diesen geklickt wird, dann wird ein und die gleiche Routine aufgerufen (entspricht der OnClientConnect). Darin fügen wir den Namen der Komponente die geklickt wird einer ListBox hinzu und als Objekt die Komponente selber (so hatte ich es). Du hast es aber nun durch deine Änderungen so gemacht, das du beim Klick den Komponentennamen der ListBox hinzufügst und die Form auf der sie liegen. Nun weiss ich aber nachher nicht mehr, welche Komponente das war, wenn ich später mal in der ListBox nachschaue. Egal wo ich nachschaue, in jedem Eintrag der ListBox steht die Form drinne, aber das interessiert mich nicht, die habe ich und die ist eh immer gleich. Ich will da direkt die Komponente haben...

Für die Analogien:

Form = ServerSocket1 (TServerSocket)
Komponente = Socket (TCustomWinSocket) Instanz

MfG
Muetze1

PierreB 30. Dez 2004 17:48

Re: Server disconnectet Client
 
Zitat:

Angenommen wir haben mehrere Komponenten auf einer Form und immer wenn auf einer von diesen geklickt wird, dann wird ein und die gleiche Routine aufgerufen (entspricht der OnClientConnect). Darin fügen wir den Namen der Komponente die geklickt wird einer ListBox hinzu und als Objekt die Komponente selber (so hatte ich es). Du hast es aber nun durch deine Änderungen so gemacht, das du beim Klick den Komponentennamen der ListBox hinzufügst und die Form auf der sie liegen. Nun weiss ich aber nachher nicht mehr, welche Komponente das war, wenn ich später mal in der ListBox nachschaue. Egal wo ich nachschaue, in jedem Eintrag der ListBox steht die Form drinne, aber das interessiert mich nicht, die habe ich und die ist eh immer gleich. Ich will da direkt die Komponente haben...
Also deshalb geht das kicken jetzt nicht mehr, ja?

Könnte man dann nicht mit ner for-Schleife alle Komponenten (also alle Sockets) durchgehen und wenns die richtige ist, den User rauswerfen ?

Muetze1 30. Dez 2004 17:54

Re: Server disconnectet Client
 
Moin!

Zitat:

Zitat von delphman
Zitat:

Angenommen wir haben mehrere Komponenten auf einer Form und immer wenn auf einer von diesen geklickt wird, dann wird ein und die gleiche Routine aufgerufen (entspricht der OnClientConnect). Darin fügen wir den Namen der Komponente die geklickt wird einer ListBox hinzu und als Objekt die Komponente selber (so hatte ich es). Du hast es aber nun durch deine Änderungen so gemacht, das du beim Klick den Komponentennamen der ListBox hinzufügst und die Form auf der sie liegen. Nun weiss ich aber nachher nicht mehr, welche Komponente das war, wenn ich später mal in der ListBox nachschaue. Egal wo ich nachschaue, in jedem Eintrag der ListBox steht die Form drinne, aber das interessiert mich nicht, die habe ich und die ist eh immer gleich. Ich will da direkt die Komponente haben...
Also deshalb geht das kicken jetzt nicht mehr, ja?

Könnte man dann nicht mit ner for-Schleife alle Komponenten (also alle Sockets) durchgehen und wenns die richtige ist, den User rauswerfen ?

Genau deshalb, ja.

Und zu der Schleife: Warum nicht einfach immer den jeweiligen Socket zum ListBox Eintrag hinzufügen? Dann ist es so einfach wie eh und je...
Und selbst mit der Schleife: woher wissen das der jeweilige Eintrag der richtige ist?

MfG
Muetze1

PierreB 30. Dez 2004 17:57

Re: Server disconnectet Client
 
Aber bloß wie ??? :gruebel:

Geht das eine, geht das andere nicht mehr ! :wall:


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:31 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz