![]() |
SocketServer & mehrere Clients verwalten
Hallo,
habe ein hoffentlich kleines nur Problemchen. Ich nutze einen SocketServer und mehrere Clients. Die Client <-> Server Verbindung steht und Funktioniert prächtig. Was mir jetzt fehlt ist über den Server eine Client <- Server -> Client Verbindung. Wie ich eine Nachricht an den jenigen schicke der grad eine Anfrage an den Server stellt ist auch kein Problem, nur wie bekomme ich den Server dazu das er dann von da aus die Nachricht an Client 'X' weiterleiten soll. Die Clients kann ich alle per Protokoll identifizieren, z.B. wird dabei immer der PC-Name mit gesendet, zusätzlich habe ich noch die IP. Aber ich weiss nicht wie ich herausbekomme Client 'X' direkt anzusprechen. Hatte mir überlegt ich schicke es an jeden Client und verarbeite es da, nach dem Motto
Delphi-Quellcode:
Doch wenn dann mal so 50 Rechner angemeldet sind, kommt da bei jedem schon ungehäuer Traffic auf,
IF PC-Name = MyOwn THEN...
der nicht wirklich sein müsste. Hatte auch schon gedacht über
Delphi-Quellcode:
aber selbst
Socket.Connections[n]
da muss man bei 50 Rechnern wenn jemand die Verbindung trennt die ID's neu belegen, bis zu dem der trennte. Gibt es eine Lösung womit ich wirklich nur das nötigste an Traffic verursache eben genau die vom Server <-> Client und ohne das ich manuell eine riesen ID-Struktur selber anlegen müsste? Sitze hier schon länger dran und komm nicht auf einen grünen Zweig... Gruss Cyb |
Re: SocketServer & mehrere Clients verwalten
Hallo Cyberaxx,
für eine bidirektionale Kommunikation musst du in deinem Programm beide Komponenten betreiben - SocketServer und SocketClient. Grüße vom marabu |
Re: SocketServer & mehrere Clients verwalten
Ich habe mir dafür eine Klasse geschrieben, sodass die Apps mit Hilfe von mailslots kommunizieren können.
Wenn deine Clients und der Server in einer Domäne hängen, klappt das wunderbar, bei einer Arbeitsgruppe weiss ich es nicht. Auf meinen Clients habe ich einen mailslot namens 'Rcv' eingerichtet. Ein thread setzt sich drauf und wartet, bis eine Nachricht eingetroffen ist (max 1k), dann wird ein Event abgefeuert. Man kann die mailslots auch pollen, also schauen, ob und wie gross die nachricht ist, dann einen Buffer aufmachen und die Daten dann abholen. Wenn ich nun zum PC 'FooBar' eine Nachricht schicken will, dann schreibe ich die einfach an:'\\FooBar\.\mailslots\Rcv' und -bups- purzelt sie auf der anderen Seite raus.
Delphi-Quellcode:
Hier ist der MailReceiver, also ein Thread, der auf eine mail wartet:
///////////////////////////////////////////////////////////////////////////////
// SendMail: Send a Mail 'aMessage' to the Mailslot 'aSlotName' on the // // Machine 'aComputer' // /////////////////////////////////////////////////////////////////////////////// Procedure SendMail (aComputer, aSlotName, aMessage : String); var Bytes: DWord; aPath : String; aHandle : THandle; begin aPath := '\\' + aComputer + '\mailslot\' + aSlotName; aHandle := CreateFile(PChar(aPath), GENERIC_WRITE, FILE_SHARE_READ, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); try if aHandle = INVALID_HANDLE_VALUE then Raise EInOutError.CreateFmt('Cannot create mailslot %s\%s',[aComputer,aSlotName]) else If not WriteFile(aHandle, Pointer(aMessage)^, Length(aMessage), Bytes, nil) Then Raise EInOutError.CreateFmt('Cannot write to mailslot %s\%s',[aComputer,aSlotName]); finally if aHandle <> INVALID_HANDLE_VALUE Then CloseHandle(aHandle); end; end;
Delphi-Quellcode:
Ach, wenn man als Empfänger ein '*' einträgt, dann wird die Mail an alle PC geschickt (also ein Broadcast).
///////////////////////////////////////////////////////////////////////////////
// Object : TMailReceiver // /////////////////////////////////////////////////////////////////////////////// constructor TMailReceiver.Create(aSlotName : String; aMaxLength : Integer); Var aPath : String; begin Inherited Create (True); fSlotName := aSlotName; fMaxLength := aMaxLength; aPath := '\\.\mailslot\' + aSlotName; fHandle := CreateMailSlot(PChar(aPath), 0, MAILSLOT_WAIT_FOREVER, nil); if fHandle = INVALID_HANDLE_VALUE Then // Raise Exception.Create ('Could not create mailslot, slotname already exists'); end; destructor TMailReceiver.Destroy; begin Terminate; CloseHandle (fHandle); end; procedure TMailReceiver.DoOnMailReceived; begin Try if Assigned (fOnMail) And (Length (fMessage)>0 ) Then fOnMail (Self, fMessage); Except End; end; procedure TMailReceiver.Execute; Var aSize : DWord; begin While Not Terminated Do Begin SetLength (fMessage, fMaxLength); if ReadFile(fHandle, PChar(fMessage)^, fMaxLength, aSize, nil) Then If not terminated Then SetLength (fMessage, aSize); if not terminated then Synchronize (DoOnMailReceived); End end; procedure TMailReceiver.Start; begin Resume; end; procedure TMailReceiver.Stop; begin Try Terminate; SetMailslotInfo (fHandle,0); Except End; end; Du erzeugst den TMailReceiver und startest den mit 'Start' (logisch), z.B. im FormCreate oder DatamoduleCreate. Im flxrmgfDestroy stoppst du den TMailReceiver und schmeisst in Free technisch weg. Du kannst natürlich mehrere Mailslots einrichten, sodass Du verschiedene Subsysteme realisieren kannst. Usw. Das geht natürlich alles bestimmt viel eleganter (per UDP?), aber das ist mir alles zu blöd gewesen. so ist es simpel, überschaubar und funzen tut es auch ;-) |
Re: SocketServer & mehrere Clients verwalten
@Marabu
Wieso muss ich das? Es ist beabsichtigt das es immer über den Server geht. Der Server übernimmt praktisch die ganze Verwaltungsarbeit. Es geht ja auch das über den Server mehrere Clients auch untereinander komunizieren können ich will nur nicht den Weg des größten Traffics oder der ganzen adressiererei mit den ID's beim connecten und verlassen des Servers gehen. Er soll jediglich dem Client PC0078 eine eindeutige ID geben mit der ich immer sagen kann, wenn jemand mit PC0078 reden will, das der Server weiss aha PC0078 hat ID = 1 also
Delphi-Quellcode:
Socket.Connections[1].SendText(S);
@Alzaimar Klingt soweit nicht schlecht. Es soll sich hierbei aber nicht nur im eine 'chatartige' komunikation handeln, sondern später auch Dateien übertragen werden(Update Funktion von Programmen), da kann es dann auch mal zu einer grossen Datenmenge kommen. Die Clients hängen auch leider nicht alle an einer Domäne. Klingt jetzt doof aber auf der Keramik hat man ja bekanntlich die besten Ideen... Ich weiss auch nicht wieso ich da erst jetzt drauf komme aber ich werds jetzt mal einfügen, vllt. gibt es ja noch eine einfachere Methode, hoff ich... Wenn eine Nachricht für für den Client 'X' auftaucht, starte ich einfach eine Schleife und lasse ihn suchen Beim connecten wird der IP ein PC-Name zugeordnet, hier eben PC0078
Delphi-Quellcode:
Problem dabei ist wenn mehrere Clients die Selbe IP nutzen gibt es schon Probleme. :(
FOR n := 0 to MaxConnections DO BEGIN
IF Socket.Connections[n].RemoteAddress = Client 'X' Adresse THEN .... NEXT; |
Re: SocketServer & mehrere Clients verwalten
Ich habe mein mailkonzept auch nicht zum übertragen grösserer Datenmengen gedacht, sondern zur Kommunikation.
Du kannst doch dem Client, mit dem du dich mal 'ernsthaft' unterhalten willst, folgende Mail schicken:
Code:
Daraufhin baut der Empfänger einen Socket auf Port 12345 zur Adresse 192.168.123.001 auf und wartet auf weitere Instruktionen. Über ein geeignetes a) Mail-Format oder b) Übertragungsformat auf IP-Ebene verschickst du dann einfach Deine Daten. Anschließend wird der Socket wieder entfernt und fettich.
REQUEST CONNECT
Host 192.168.123.001 Port 12345 Ich habe das (Mail-)Konzept benutzt, um meinen Clients mitzuteilen, das sich wichtige (Kunden-)Daten auf dem Server verändert haben und sie doch bitteschön mal bei Gelegenheit ein Refresh ausführen sollen. Wenn Du bidirektionale Kommunikation mit einem SocketServer haben willst, müssen deine Clients Connectionpoints implementieren, oder einfach alle paar Sekunden nachfragen, ob's denn eine Nachricht gibt ... Du implementierst auf Serverseite zwei kleine Methoden:
Delphi-Quellcode:
Mit SendMail schickst Du eine kleine Mail an irgendjemanden. Der Server puffert sie und übergibt sie an den Empfänger. Da kann dann wieder sowas drinstehen, wie:'Ey, mach mal ein Socket auf, ich hab was für Dich' oder so.
Procedure SendMail (Const aSender, aRecipient, aText : String);
Function GetMail (aMyID : String; Var aSender, aText : String) : Boolean; |
Re: SocketServer & mehrere Clients verwalten
Hallo,
guck dir mal das hier an: ![]() Es werden alle verbundenen Clients in eine Liste aufgenommen und an ihrem Index in der Liste identifiziert. Im Prinzip wird bei jedem OnConnect oder OnDisconnect Ereigniss die ActiveConnections Liste in einer Schleife abgearbeitet. In dieser Schleife sendet der Server einen Anfrage String erst an Client ID 0. Wenn Client 0 auf die Anfrage geantwortet hat, wird er in die Liste mit Computernamen, etc eingetragen und die Schleife wird fortgeführt. Florian |
Re: SocketServer & mehrere Clients verwalten
Werd ich mir gleich mal ansehen. Bin jetzt gerade dabei zu versuchen es über den SocketHandel zu regeln, zumindest versuch ich es.
Es ist alles recht umständlich da auch ich immer wieder die Liste der Connections durchgehen muss. |
Re: SocketServer & mehrere Clients verwalten
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:28 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz