Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   TServer/Client -Socket Datenaustausch (https://www.delphipraxis.net/187895-tserver-client-socket-datenaustausch.html)

PetziBaer 13. Jan 2016 10:49

TServer/Client -Socket Datenaustausch
 
Hallo,

bevor mir jemand den Kopf abreißt, leider bin ich im Netz nicht fündig über eine passende Antwort auf meine Frage geworden.
Ansätze konnte ich mir zusammensuchen aber letzendlich fehtl mir noch etwas.

Zu meinem eigentlichen Vorhaben:

Ich schreibe zur Zeit eine Chat-Applikation mit folgenden Features:
  • Login
  • Logout
  • Message an alle
  • Message privat
  • (Datentransfer)

Bisher können User:
  • sich anmelden
  • sich abmelden
  • Nachricht an alle schicken

Der Server listet in einer TListBox alle User mit ID und Namen auf.
Diese Date, bzw. nur die Namen, sollen an die Clienten übermittelt werden, damit diese ebenfalls eine ListBox mit den Usern haben.

Messages schreibe ich momentan wie folgt:
Code:
type
  TChatMessage = packed Record
    Text : String[255];
    User : String[255];
    Command : Integer;
  End;


//SENDEN

procedure TForm2.cmd_SendClick(Sender: TObject);
begin
  chatMessage.Text := txt_Send.Text;
  chatMessage.Command := 2;
  txt_Send.Text := '';

  Client.Socket.SendBuf(chatMessage, SizeOf(chatMessage));
end;


//EMPFANGEN

Socket.ReceiveBuf(chatMessage, SizeOf(chatMessage));

  case TCommandEnum(chatMessage.Command) of

    MsgAll:
      begin
        mem_Log.Lines.Add(chatMessage.User + ': ' + chatMessage.Text);
        ...
Jetzt bin ich an dem Punkt angekommen, wo ich die (Daten der) ListBox senden will. Allerdings weiß ich nicht wie ich das machen kann. Das Senden und Empfangen eines Steuerelements wird wohl auch über SendBuf funktionieren. Nur muss ich unterscheiden ob gerade ein Text oder die ListBox-Daten gesendet werden.

Ich hoffe das Problem habe ich verständlich geschildert.

Ich möchte dies gern mit TServerSocket bzw TClientSocket fertig machen bevor hier wieder von INDY oder ähnlichen die Rede ist. Mag sein das es dort fertige Methoden gibt oder so, aber ich will vorerst mit den ServerSocket arbeiten.

Mfg

PetziBaer 14. Jan 2016 08:53

AW: TServer/Client -Socket Datenaustausch
 
Ich habe das Programm mitlerweile erweitert (erweitern wollen).

Gedanke war, das Record um ein String-Array zu erweitern und dort die Items der ListBox zu speichern.
Leider lässt sich die Größe des Arrays nicht bestimmen. Das progamm schmiert immer an der Stelle ab.

Fehlermeldung:
Im Projekt P_Server.exe ist eine Exception der Klasse EAccessViolation mit der Meldung 'Zugriffsverletzung bei Adresse 00403400 in Modul 'P_Server.exe'. Lesen von Adresse 00000000' aufgetreten.

Der Code sieht folgendermaßen aus:

Code:
type
  TChatMessage = packed Record
    Text : String[255];
    User : String[255];
    Clients : Array of String;
    Command : Integer;
  End;
...

var
  i : Integer;
begin
  listbox.Clear();

  for i := 0 to clientList.Count -1 do
  begin
    listbox.Items.Add(IntToStr(clientList.Items[i].SocketID) + ' ' + clientList.Items[i].Username);
  end;

  chatMessage.Command := 4;                              //4 = ListBox Update

  SetLength(chatMessage.Clients, listBox.Items.Count);   //HIER KOMMT DER FEHLER!

  for i := 0 to listBox.Items.Count -1 do
  begin
    chatMessage.Clients[i] := listBox.Items[i];
  end;

  for i := 0 to Server.Socket.ActiveConnections -1 do
  begin
    Server.Socket.Connections[i].SendBuf(chatMessage, SizeOf(chatMessage));
  end;
Ich denke vom Ansatz wird das funktionieren. Allerdings kann ich mir nicht erklären wieso dieser Fehler auftritt.

Im übrigen wäre ich auch über andere Vorhergehensweisen für einen solchen Prozess dankbar, sofern man dadurch vielleicht "sauberer" programmiert.

Mfg

mjustin 14. Jan 2016 08:59

AW: TServer/Client -Socket Datenaustausch
 
Das array of String wurde nicht initialisiert, daher erfolgt die AV. Abgesehen davon kann ein ClientSocket den String nicht übertragen, da er nur als Pointer (Speicheradresse) im record enthalten ist. Die anderen Strings sind als ShortStrings dagegen richtig implementiert :)

Bernhard Geyer 14. Jan 2016 09:10

AW: TServer/Client -Socket Datenaustausch
 
Zitat:

Zitat von PetziBaer (Beitrag 1326970)
Ich denke vom Ansatz wird das funktionieren.

Nein!

Dein
Delphi-Quellcode:
  Clients : Array of String;
im Record
kann so nicht übertragen werden da für die einzelnen String hier nur die Pointer auf den Adressbereich übertragen wird statt der String.
Du musst eine Serialisierte Darstellung deinens Strings schaffen.

Entweder mit
Delphi-Quellcode:
  Clients : Array of String[255];
arbeiten oder eine passende (De-)Serialisierungsfunktion schreiben

PetziBaer 14. Jan 2016 10:50

AW: TServer/Client -Socket Datenaustausch
 
Habe das Problem jetzt gelöst.

Mein Record besteht nun aus einem extra String für die Clients.

Code:
type
  TChatMessage = packed Record
    Text : String[255];
    User : String[255];
    Destination : String[255];
    Clients : String[255];
    Command : Integer;
  End;
Zur Zeit lese ich jedes Item der ListBox einzeln aus, hänge es an den String hinten an und trenne die Items durch ein Semikolon.

Code:
for i := 0 to listBox.Items.Count -1 do
  begin
    chatMessage.Clients := chatMessage.Clients + listBox.Items[i] + ';';
  end;
Der Client trennt diesen String jetzt anhand der Semikolons.

Code:
procedure Split(Delimiter: Char; Str: string; ListOfStrings: TStrings);
begin
   ListOfStrings.Clear;
   ListOfStrings.Delimiter      := Delimiter;
   ListOfStrings.StrictDelimiter := True;
   ListOfStrings.DelimitedText  := Str;
end;
...

  splitData := TStringList.Create();
  Split(';', chatMessage.Clients, splitData);
Ankommen tut nun alles richtig, frage mich allerdings immernoch ob es eventuell eine bessere/schönere Möglichkeit gibt.

Ziel ist es das später auch Dateien versendet werden sollen und wenn ich so weiter mache komme ich wohl sehr bald an die Grenzen. (schätze ich)

Habe mal angefangen mich mit dem Thema Stream auseinander zu setzen, allerdings gibt es da noch die ein oder anderen Fragezeichen bei mir.

Sir Rufo 14. Jan 2016 11:56

AW: TServer/Client -Socket Datenaustausch
 
BTW

Für Delphi Code gibt es die
Code:
[DELPHI]
[/DELPHI]
Tags, die den Code dann auch farblich besser darstellen.

Beispiel:
Delphi-Quellcode:
type
  TChatMessage = packed Record
    Text : String[255];
    User : String[255];
    Destination : String[255];
    Clients : String[255];
    Command : Integer;
  End;

PetziBaer 14. Jan 2016 12:17

AW: TServer/Client -Socket Datenaustausch
 
Dankeschön, werde ich beim nächsten mal berücksichtigen. :thumb:
Nach dem Post habe ich auch direkt den alten Römerhelm im Editor entdeckt :idea:


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:45 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