Entwickler-Ecke

Internet / Netzwerk - TStringList übers LAN Senden!


pyr0t0n - Di 19.06.07 19:36
Titel: TStringList übers LAN Senden!
Aloa,

ich habe ne kleine Frage. Wie kann ich eine TStringList per Socket Komponenten übertragen? und auf der Anderen Seite wieder in einem TStringList bzw einer ListBox darstellen ?

hat da einer ne idee zu ?

Danke schonmal

Mfg
pyr0


Narses - Di 19.06.07 19:48

Moin!

Schau mal hier [http://www.delphi-library.de/topic_54269.html] :les: damit solltest du weiter kommen. ;)

cu
Narses


pyr0t0n - Di 19.06.07 19:54

Also erstmal DANKE

aber gibts da auch ne einfachere möglichkeit ohne gleihc ein Protokoll zu entwerfen? also konnte die TStrings nun in einen TStream umwanden und senden geht ja dann mit Socket.SendStream doch der empfang auf der anderen seite macht mir noch probs.

gruß
pyr0


Narses - Di 19.06.07 19:58

Moin!

user profile iconpyr0t0n hat folgendes geschrieben:
Also erstmal DANKE

Bitte. ;)

user profile iconpyr0t0n hat folgendes geschrieben:
aber gibts da auch ne einfachere möglichkeit ohne gleihc ein Protokoll zu entwerfen?

IMHO - nein. :|

user profile iconpyr0t0n hat folgendes geschrieben:
also konnte die TStrings nun in einen TStream umwanden und senden geht ja dann mit Socket.SendStream doch der empfang auf der anderen seite macht mir noch probs.

Genau, deshalb solltest du mal hier [http://www.delphi-library.de/topic_Warum+gibt+es+kein+ReceiveStream+bei+den+Sockets_65367.html] und hier [http://www.delphi-library.de/topic_Datenpakete+bei+den+SocketKomponenten+auseinanderhalten_56194.html] nachlesen :les: warum das so ist. :D

Eine Alternative wären die TNBFPA-Komponenten [http://www.delphi-forum.de/topic_71223.html], damit kannst du dir das ganze Protokoll-Geraffel vom Hals halten und dich auf das Andere konzentrieren. Hier ein Beispiel, wie einfach es damit ginge: ;)

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:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, NarsesBFPA, StdCtrls;

const
  CMD_ListBox = 1;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    ListBox2: TListBox;
    Button1: TButton;
    NBFPAClient1: TNBFPAClient;
    NBFPAServer1: TNBFPAServer;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure NBFPAServer1ClientExecute(Sender: TObject;
      PA: TProtocolAdapter);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  NBFPAServer1.Open;
  Application.ProcessMessages;
  NBFPAClient1.Connect;
end;

procedure TForm1.Button1Click(Sender: TObject);
  var
    Cmd: TCmdSeq;
begin
  Cmd := TCmdSeq.Create(CMD_ListBox);
  Cmd.Add(ListBox1.Items);
  NBFPAClient1.SendAndFree(Cmd);
end;

procedure TForm1.NBFPAServer1ClientExecute(Sender: TObject; PA: TProtocolAdapter);
  var
    i: Integer;
begin
  case PA.CurrentToken of
    CMD_ListBox:
      begin
        ListBox2.Clear;
        for i := 1 to PA.CurrentArgCount-1 do
          ListBox2.Items.Add(PA.Inbound.Strings[i]);
      end;
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  NBFPAClient1.Disconnect;
  Application.ProcessMessages;
  NBFPAServer1.Close;
end;

end.

cu
Narses


pyr0t0n - Di 19.06.07 20:14

Naja vllt sollte ich mein prob doch nochmal weiter erläutern,

also ich habe mehrere Clienten auf denen ich die Windows Prozess liste abrufen kann das geschieht über diese Funktion:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure GetProcessList(const aProcessList: TStrings);
var
  Snap: THandle;
  ProcessE: TProcessEntry32;
begin
  aProcessList.Clear;
  Snap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  try
    ProcessE.dwSize := SizeOf(ProcessE);
    if Process32First(Snap, ProcessE) then
      Repeat
        aProcessList.Add(ProcessE.szExeFile);
      Until not Process32Next(Snap, ProcessE)
    else
      RaiseLastOSError;
  finally
    CloseHandle(Snap);
  end;
end;


aufrufen halt über:


Delphi-Quelltext
1:
GetProcessList(ProzessListe);                    


wobei ich ProzessListe vorher schon so deklariert habe


Delphi-Quelltext
1:
var ProzessListe: TStrings;                    


sodale soweit so gut.

Aufdem Server Rechner soll halt diese Liste in einer ListBox wieder angezeigt werden. Und in der übertragung sowie auswertung liegt nun mein problem.

Das Tutorial mit dem Terminator Trennzeichen ist ja nicht schlecht hab mit die Funktion mit dem Senden der UserListe angesehen, aber
ich habe ja bei meiner Tstring überhaupt nicht die erweiterung von .Items geschweige denn .CommaText.

Somit steh ich wieder auf dem schlauch.

Gruß
pyr0

PS: Manch einer mag vllt denken das das hier für einen Trojaner Selbstbau ist dem muss ich aber verneinen das programm soll auf einer LAN zum einsatz kommen und ich möchte cheatern etwas vorbeugen indem ich mir bei Report deren Prozessliste ansehen kann.


Narses - Di 19.06.07 20:17

Moin!

user profile iconpyr0t0n hat folgendes geschrieben:
wobei ich ProzessListe vorher schon so deklariert habe

Delphi-Quelltext
1:
var ProzessListe: TStrings;                    

Laut DOH soll man TStringsnicht direkt instanziieren! :mahn: :| Also besser TStringList! :idea:

Ansonsten siehe mein letzter Beitrag. ;)

cu
Narses


pyr0t0n - Di 19.06.07 20:36

Also selbst wenn ich aus TString dann TStringList mache habe ich dieses .Items nicht!?! mache ich denn was falsch ?


Narses - Di 19.06.07 20:40

Moin!

user profile iconpyr0t0n hat folgendes geschrieben:
Also selbst wenn ich aus TString dann TStringList mache habe ich dieses .Items nicht!?! mache ich denn was falsch ?

Jain ;) TStringListist ein Nachfahre von TStrings, genau so wie z.B. TListBox.Itemsein Nachfahre von TStringsist. Also hat TStringListschon die Eigenschaften .CommaText, .Text, etc.pp. :idea: Schau doch mal in die DOH... :roll: :les: ;)

Auf das TNBFPA-Beispiel oben bezogen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure TForm1.Button1Click(Sender: TObject);  
  var  
    SL: TStringList;
    Cmd: TCmdSeq;  
begin  
  SL := TStringList.Create;
  try
    SL.Add('Test1');
    SL.Add('Test2');
    Cmd := TCmdSeq.Create(CMD_ListBox);  
    Cmd.Add(SL);  
    NBFPAClient1.SendAndFree(Cmd);
  finally
    SL.Free;
  end;
end;

cu
Narses


pyr0t0n - Di 19.06.07 20:51

also die funktion sieht bei mir nun so aus


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
GetProcessList(ProzessListe);
try
Cmd := TCmdSeq.Create(CMD_ListBox);
Cmd.Add(ProzessListe);
NBFPAClient1.SendAndFree(Cmd);
finally
ProzessListe.Free;
end;
end;


doch sobald die im client aufgerufen wird bekomme ich

Access violation at address 00458A78 in module 'Client.exe' Read of address 00000000.


Narses - Di 19.06.07 20:55

Moin!

user profile iconpyr0t0n hat folgendes geschrieben:
also die funktion sieht bei mir nun so aus

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
GetProcessList(ProzessListe);
try
Cmd := TCmdSeq.Create(CMD_ListBox);
Cmd.Add(ProzessListe);
NBFPAClient1.SendAndFree(Cmd);
finally
ProzessListe.Free;
end;

end;

doch sobald die im client aufgerufen wird bekomme ich
Debugger hat folgendes geschrieben:
Access violation at address 00458A78 in module 'Client.exe' Read of address 00000000.

Das darfst du natürlich nur dann tun, wenn deine Prozessliste eine lokale Variable ist; wenn die Liste global ist, dann gibst du sie ja entweder zu früh bzw. mehrfach frei :shock: und das gibt natürlich was auf die Finger. :P

Aber mal so am Rande: du meinst nicht, dass ein oder zwei OOP-Tutorials dir gut tun würden... :? :?:

cu
Narses


pyr0t0n - Di 19.06.07 20:57

Zitat:

Aber mal so am Rande: du meinst nicht, dass ein oder zwei OOP-Tutorials dir gut tun würden... :? :?:


joa bestimmt aber mache delphi eigentlich nur wenn ich schnell was brauche lerne atm c++ ^^

EDIT:

Also habe das Free rasgenommen fehler bleibt allerdings.


Narses - Di 19.06.07 21:05

Moin!

user profile iconpyr0t0n hat folgendes geschrieben:
Also habe das Free rasgenommen fehler bleibt allerdings.

Mehr Code, bitte. :|

cu
Narses


pyr0t0n - Di 19.06.07 21:12

kk kommt...

Also nochmal die Funktion GetProcessList


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure GetProcessList(const aProcessList: TStringList);
var
  Snap: THandle;
  ProcessE: TProcessEntry32;
begin
  aProcessList.Clear;
  Snap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  try
    ProcessE.dwSize := SizeOf(ProcessE);
    if Process32First(Snap, ProcessE) then
      Repeat
        aProcessList.Add(ProcessE.szExeFile);
      Until not Process32Next(Snap, ProcessE)
    else
      RaiseLastOSError;
  finally
    CloseHandle(Snap);
  end;
end;


Dann nochmal der Teil der mir die Liste senden soll, es muss an einem der 2 Sachen liegen, weil der fehler auftritt sobald ich den Button zum senden drücke.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
procedure TForm1.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
var antwort : STRING;
var Cmd: TCmdSeq;
begin
antwort := Socket.ReceiveText;

[...]

if antwort = 'PROZLIST' then begin
  GetProcessList(ProzessListe);
  try
    Cmd := TCmdSeq.Create(CMD_ListBox);
    Cmd.Add(ProzessListe);
    NBFPAClient1.SendAndFree(Cmd);
  finally;
  end;
end;


hoffe des reicht dir weil viel mehr hab ich gar nicht. und auhc nix was irgendein Free hat ^^


Narses - Di 19.06.07 22:07

Moin!

user profile iconpyr0t0n hat folgendes geschrieben:
Dann nochmal der Teil der mir die Liste senden soll, es muss an einem der 2 Sachen liegen, weil der fehler auftritt sobald ich den Button zum senden drücke.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
procedure TForm1.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
var antwort : STRING;
var Cmd: TCmdSeq;
begin
antwort := Socket.ReceiveText;

[...]

if antwort = 'PROZLIST' then begin
  GetProcessList(ProzessListe);
  try
    Cmd := TCmdSeq.Create(CMD_ListBox);
    Cmd.Add(ProzessListe);
    NBFPAClient1.SendAndFree(Cmd);
  finally;
  end;
end;

:shock: Ähm, das sieht so aus, als hättest du da die Komponenten "vermischt"?! :?!?: Also, du darfst NUR die TNBFPA-Kompos ODER die Sockets direkt nehmen, nicht beides durcheinanderbringen! :mahn:

cu
Narses


pyr0t0n - Di 19.06.07 22:12

hm.. doch habs hinbekommen

und zwar hab ich einfach beim Clienten der die ProzessListe senden soll eine ListBox gemacht welche halt unsichtbar ist, dort hatte ich dannauch die funktion Items und komischerweise gehts nun auch..

trotzdem nochmal vielen dank.

aber eine frage hab ich noch...

wie kann ich mit deinen kompos normalen text senden und diesen auswerten ala

wenn gesendeter text = blubb mache das und das

über normale sockets ja

socket.sendtext(STRING) und Socket.ReceiveText

aber wie bei deinen ?


Narses - Di 19.06.07 22:29

Moin!

user profile iconpyr0t0n hat folgendes geschrieben:
und zwar hab ich einfach beim Clienten der die ProzessListe senden soll eine ListBox gemacht welche halt unsichtbar ist, dort hatte ich dannauch die funktion Items und komischerweise gehts nun auch.

:?!?: ich fürchte, du hast keine Ahnung, was du da machst... :? oder? 8)

user profile iconpyr0t0n hat folgendes geschrieben:
trotzdem nochmal vielen dank.

Bitte bitte, aber lies dir einfach mal die Protokoll-Tuts durch, ja? :|

user profile iconpyr0t0n hat folgendes geschrieben:
aber eine frage hab ich noch...

wie kann ich mit deinen kompos normalen text senden und diesen auswerten ala

Das läuft bei den TNBFPA-Kompos nicht über Text, sondern über die Kommando-Token (diese const CMD_ListBox = 1; Geschichte), dafür brauchst du keinen Text. :idea: Bitte Details im BinProto-Tut [http://www.delphi-library.de/topic_66706.html] nachlesen. :les:

user profile iconpyr0t0n hat folgendes geschrieben:
wenn gesendeter text = blubb mache das und das

über normale sockets ja

socket.sendtext(STRING) und Socket.ReceiveText

So wie du das ansetzt, ist das eh "falsch", weil du von den Ereignissen nicht auf Datenpaketgrenzen schließen kannst/darfst, das klappt immer nur "zufällig", Details hier [http://www.delphi-library.de/topic_56194.html]. Weiterhin bekommst du Probleme, wenn die Datenrate so hoch wird, dass der WSA-Puffer voll läuft, dann liest du mit einem Socket.ReceiveText nämlich immer nur 8kb, und nicht alles, was bisher eingetroffen ist! :mahn: Insgesamt also: besser Finger von lassen und ein Protokoll nehmen (was mit den TBNFPA-Kompos ja nun wirklich ein Kinderspiel ist, einfach für die Befehle Konstanten definieren und die Parameter an die Sequenz hängen, fertig. Den TClientSocket und den TServerSocket brauchst du dann gar nicht mehr im Projekt. :D)

cu
Narses


pyr0t0n - Mi 20.06.07 18:08

ok Narses eine letzte frage hab ihc aber noch in deinem Code / PDF sendet der Server nur an alle Clienten, was ist wenn ich ein bestimmtes Commando nur an EINEN clienten senden will den ich vorher auf ner ListBox auswähle? also das mit der Listbox krieg ich hin aber das senden an sich an nur einen Clienten.


Narses - Mi 20.06.07 18:20

Moin!

user profile iconpyr0t0n hat folgendes geschrieben:
in deinem Code / PDF sendet der Server nur an alle Clienten,

Das stimmt nicht ganz ;) hier wird nur an einen was gesendet (den "Neuen"; Auszug aus dem Demo-Code):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
// Neuer Client: bisherige Benutzerliste an den Neuen senden
procedure TServerMain.NBFPAServer1ClientConnect(Sender: TObject;
  PA: TProtocolAdapter);
  var
    Cmd: TCmdSeq;
    i: Integer;
begin
  // alle Verbindungen des Servers durchgehen...
  for i := 0 to NBFPAServer1.Connections.Count-1 do
    // ist die betrachtete Verbindung (i) die Neue?
    if (NBFPAServer1.ConnectionByIndex[i] <> PA) then begin // nein, dann...
      Cmd := TCmdSeq.Create(CMD_USERDATA); // Details der Verbindung einsammeln
      Cmd.Add(NBFPAServer1.ConnectionByIndex[i].SessionID);
      Cmd.Add(NBFPAServer1.ConnectionByIndex[i].SessionName);
      PA.Outbound.AddCmdAndFree(Cmd); // und dem neuen Client mitteilen
    end;
  // .Send ist nicht notwendig, weil kurz nach dem OnConnect eh ein OnSession-
  // NameChange-Ereignis eintritt, in dem auch an den neuen Client gesendet wird.
end;

user profile iconpyr0t0n hat folgendes geschrieben:
was ist wenn ich ein bestimmtes Commando nur an EINEN clienten senden will den ich vorher auf ner ListBox auswähle?

Konkret auf deinen Fall angepasst:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  var
    Cmd: TCmdSeq;
begin
  Cmd := TCmdSeq.Create(... blah;
  NBFPAServer1.ConnectionsByIndex[i].Outbound.AddCmdAndFree(Cmd);
  NBFPAServer1.ConnectionsByIndex[i].Send;

Damit wird das Kommando an die i-te Verbindung gesendet. :idea: ;)

cu
Narses