Entwickler-Ecke

Internet / Netzwerk - Server soll einzelnen Client eindeutig identifizieren?


Sithlord - Mo 28.12.09 15:03
Titel: Server soll einzelnen Client eindeutig identifizieren?
Hallo Mitglieder,

bin grad dabei ein kleines Server/Client Programm zu schreiben. Nun sendet z.b. ein Client einen Befehl zum Server, der diesen dann veranlagt, an einen bestimmten Clienten etwas zu senden. Von jedem angemeldeten Clienten habe ich die eindeutige IP Adresse in einer Listbox gespeichert.

Meine Frage:
Wie veranlasse ich den Server, nur an den einen Clienten einen Befehl zu schreiben - die anderen Clienten müssen aber verbunden bleiben.

Mfg Sithlord

Moderiert von user profile iconNarses: Überflüssige Zeilenumbrüche/Leerzeilen entfernt.


Xentar - Mo 28.12.09 15:51

Du hast ne wichtige Info vergessen:
Mit welcher Komponente arbeitest du? Indy? Wenn ja, welche Version? Oder die normalen Server und ClientSocket ?


Astat - Mo 28.12.09 16:07

user profile iconSithlord hat folgendes geschrieben Zum zitierten Posting springen:
..
Von jedem angemeldeten Clienten habe ich die eindeutige IP Adresse in einer Listbox gespeichert.

Meine Frage:
Wie veranlasse ich den Server, nur an den einen Clienten einen Befehl zu schreiben - die anderen Clienten müssen aber verbunden bleiben.

Mfg Sithlord


Hallo Sithlord, den Client kannst Du immer durch den zugehörigen Socket identiffizieren. D.h. "Socket" ist für einen Client immer eindeutig.
Bei Verwendung einer IP, bekommst Du Probleme, wenn mehrere Netzwerkkarten, WLan, PPP-Adapter etc. aktiv sind, und die Ermittlung der IP somit nicht immer eindeutig ist.
Um dieses Problem zu beheben, speichere Dir in jedem Connect ein Object, bzw. Record etc. mit den übermittelten Clientinfos, eine GUID ist dafür gut geeignet, in einer schnellen Hash Liste. Bei jeder Anfrage eines Clients durchsuchst Du die Liste mit dem Socket als ID und bekommst dann das vorher gespeicherte Clientobject zurück.
An einen bestimmten Client kannst Du einfach mit dem Socket zurückschreiben.
Durchsuche die Hashliste nach deinen gewünschten Parametern (IP, Rechnername, MAC, Username etc.), ermittle den Socket, und Sende die Daten mit, send(Socket,..) bei Verwendung der Socket-API, oder bei Verwendung in Komponenten meist soetwas wie Socket.Send... an den Client.

Beschriebenes Szenario funktioniert natürlich nur wenn die Sockets permanent verbunden sind.


lg. Astat

Moderiert von user profile iconNarses: Überflüssige Zeilenumbrüche/Leerzeilen entfernt.


Sithlord - Mo 28.12.09 16:50

So in etwa wollte ich das auch haben, super Idee,

es gibt nun noch ein problem: Was muss ich vom Socket den speichern lassen - damit der socket weiß an welchen Client er das schicken muss.
Oder wie veranlasse ich es, das der Socket das dann an den Clienten schreibt - muss ja bestimmt eine eindeutige Identifizierung irgendwo vorliegen...

Oh sehe es erst jetzt, die Tclient und Tserver - die stinknormalen VCL Socket komponenten von Delhpi7


Astat - Mo 28.12.09 17:25

user profile iconSithlord hat folgendes geschrieben Zum zitierten Posting springen:
So in etwa wollte ich das auch haben, super Idee,

es gibt nun noch ein problem: Was muss ich vom Socket den speichern lassen - damit der socket weiß an welchen Client er das schicken muss.
Oder wie veranlasse ich es, das der Socket das dann an den Clienten schreibt - muss ja bestimmt eine eindeutige Identifizierung irgendwo vorliegen...


Hallo Sithlord, ich gehe mal von einer Asynchronen Socketverbindung aus.

Du musst den Client-Socket, oder das ClientObject, bei Verwendung einer Komponente, speichern, den Du im Connect Event bekommst. Mit diesem Socket (Object) kannst Du dann zu jeder Zeit an einen Client Daten zurückschicken.

PS: Zeig mal den Source, dann kann gezielter geholfen werden.

lg. Astat


Sithlord - Mo 28.12.09 18:52

Hier, wollte das ein User dem anderen einen Text senden kann, der Code ist vom Server. Ich habe aber nicht gefunden was ich da speochern muss vom Sender:TObject ?

Mfg Sithlord

Hier mal der Code von der Komponente:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
procedure TForm1.serverClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
remoteip:string;
begin
remoteip:= socket.RemoteAddress;
sender.
listbox1.Items.Add('Client '+remoteip+ ' verbunden');
end;

procedure TForm1.serverClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
remoteip:string;
i:integer;
begin
remoteip:=socket.RemoteAddress;
listbox1.Items.Add('Client '+socket.RemoteAddress+' getrennt');
for i := 0 to Listbox2.items.count - 1 do begin
  if Pos(remoteip, ListBox2.Items[i]) > 0 then
    listbox2.Items.Delete(i);
  end;
end;
procedure TForm1.serverClientWrite(Sender: TObject;
  Socket: TCustomWinSocket);
var
received:string;
received2:string;
remoteip:string;
A: TStringList;
LABEL sendpong;
LABEL sendtext;
LABEL ende;
begin
A := TStringList.Create;
received:=socket.ReceiveText;
Split('|', received, A) ;
received2:=A[0];
remoteip:=socket.RemoteAddress;
listbox1.Items.Add('Befehl: '+received);
if (received='ping'then GOTO sendpong
else
if (received='sendtext'then GOTO sendtext
else
GOTO ende;
//Pong senden um zu sagen das der Server aktiv ist ;)
sendpong:
listbox1.Items.Add('Ping von ' +remoteip+ ' bekommen');
socket.SendText('pong');
listbox1.Items.Add('Pong an ' +remoteip+ ' gesendet');
//User in die Userliste adden:
listbox1.Items.Add(remoteip+' ist nun angemeldet!');
listbox2.Items.Add(remoteip);
GOTO ende;
//Sendtext - damit können sich User kleine Texte senden ^^
sendtext:
GOTO ende;
//Das Ende
ende:
A.Free;
end;


---Moderiert von user profile iconNarses: Beiträge zusammengefasst---

Im Prinzip ist es ja aufgebaut wie "flüstern" beim Chatten. Ich find bloß grad das Tutorial für einen Delphi Chat, worin man flüstern konnte, nicht mehr ;)
Wäre sehr nett wenn den jemand auftreibt ^^


Edit:

Hab nun herausgefunden, es gibt dieses Socket.activeconnetions - wird verwendet um jeden Clienten was zu schicken, wenn ich jetzt wüsste, welcher Integer der grad neu verbundene Client hat - wäre alles perfekt gelöst ;)

Mfg SIthlord


Astat - Mo 28.12.09 23:12

Hallo Sithlord, anbei ein Demo wie das gemacht werden kann.

Bei dem Demo ist noch kein Empfanhsbuffer für jeden verbundenen Client, und auch noch kein Protokoll implementiert.

Solltest Du noch weitere Hilfe brauchen, einfach Melden.

lg. Astat


Sithlord - Mo 28.12.09 23:22

Vielen, vielen Dank ;)

Aber ich steige da nicht so sehr ganz durch, sorry.
Mache dies ja alles nur Hobbymäßig und belese mich da schon ne Menge.
Ich hätte da auch noch einen Ansatz:
Es gibt ja bei diesen Komponenten dieses "Activeconnetions".
Demnach müsste jeder verbundene Client einen eindeutigen Integerwert haben.
Diesen würde ich in einer Listbox abspeichern und bei bedarf abrufen ;)
Wie find ich diesen Wert raus?
Bsp:

Delphi-Quelltext
1:
2:
3:
  // und an alle verbundenen Clients senden
  for i := 0 to ServerSocket1.Socket.ActiveConnections-1 do
    ServerSocket1.Socket.Connections[i].SendText(MyMessage);

Oder was ist eig. dieses Sockethandle - ist das auch bei jedem einzigartig oder
wie soll ich den Quelltext von dir verstehen?

Mfg Sithlord


Astat - Di 29.12.09 00:46

Moderiert von user profile iconNarses: Komplett-Zitat des letzten Beitrags entfernt.

Hallo Sithlord, ServerSocket1.Socket.Connections[i] liefert das TCustomWinSocket Object zurück.
ServerSocket1.Socket.Connections[i].SocketHandle liefert das "SocketAPI" Socket Handle.
Beide sind immer für einen Client eindeutig, wobei ein IntToStr(ServerSocket1.Socket.Connections[i].SocketHandle) am einfachsten zu handhaben ist.
Das Sockethandle habe ich nur verwendet um das zugehörige Clientobjekt in der Listbox zu suchen.
Im Hinterkopf hatte ich da eine spätere Object suche, nach einem Integer (Sockethandle), aus einer Hashlist.
Du kannst natürlich auch direkt das TCustomWinSocket Object verwenden.

lg. Astat


Sithlord - Di 29.12.09 01:29

Vielen Dank,
damit bleibt für mich nur noch als letzte Frage woher ich das i wissen kann - vl. stelle ich mich dabei auch doof an aber der erste Client bekomm ja 0, der zweite 1 usw. Aber was ist wenn der dritte geht - wird diese Lücke aufgefüllt oder nicht.

Mfg Sithlord

P.S. Vielen Dank für deine Hilfe, hast alle deine ersten Posts an meinem Problem verschwendet ^^


Astat - Di 29.12.09 06:35

Moderiert von user profile iconNarses: Komplett-Zitat des letzten Beitrags entfernt.

Hallo Sithlord, die Komponente aktualisiert automatisch die Interne Connection Liste. D.h. Wenn ein Disconnect und oder Socket Error ausgelöst wird, wird der Socket, der das verursacht, automatisch aus der Liste entfernt. Also die Lücke wird nicht ausgefüllt, sondern es wird diese entfernt. Alle nachfolgenden Einträge rücken nach, und bekommen somit um ActIndex -1, einen neuen index.
Beispiel: 1, 2, 3, 4, 5 sind vorhanden, dann wird 3 entfernt, somit werden alle > 3 um eins decrementiert 4 wird zu 3, 5 wird zu 4 usw.

Tip:
Auf Grund dieses Verhaltens, solltest Du die Schleife wo du Daten an die Client sendest, mit for i := LisBox1.items.count -1 downto 0 do .. aufbauen. Denn wenn währen des Sendens sich ein Client Disconnectet, kommt es nicht zu einer Indexverletzung.

lg. Astat

Moderiert von user profile iconNarses: Überflüssige Zeilenumbrüche/Leerzeilen entfernt.


Narses - Sa 02.01.10 02:32

Moin!

user profile iconSithlord hat folgendes geschrieben Zum zitierten Posting springen:
Im Prinzip ist es ja aufgebaut wie "flüstern" beim Chatten. Ich find bloß grad das Tutorial für einen Delphi Chat, worin man flüstern konnte, nicht mehr ;)
Wäre sehr nett wenn den jemand auftreibt
Falls du das hier gemeint hast [http://www.delphi-library.de/topic_TerminatorzeichenProtokollTutorial+Sockets+v400_54269.html]? ;)

cu
Narses


Astat - Sa 02.01.10 06:41

user profile iconNarses
http://www.delphi-library.de/topic_TerminatorzeichenProtokollTutorial+Sockets+v400_54269.html


Hallo Narses, muss schon sagen, Hut ab!! Ist eine wahnsinns Doku und Source!! Respekt!!

lg. Astat