Autor Beitrag
IhopeonlyReader
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: So 23.06.13 21:26 
Guten Tag,
ich möchte von Anwendung 1 zu Anwendung 2 etwas schicken (Stream) klappt alles problemlos..
Aber es gibt ein Problem falls mehrerer etwas schicken wollen..

Aufbau:

Client = Sender:
Einzig wichtige Procedure (steht auf ctBlocking):
ausblenden volle Höhe 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:
procedure TForm1.Button1Click(Sender: TObject);
begin
Color := clLime;
Application.ProcessMessages;
  Client.Host := Edit1.Text;
  try
  Client.Port := StrToInt( Edit2.Text );
    except
    Showmessage( 'Fehlerhafter Port' );
    Color := clBtnFace;
    exit;
    end;

  try
  Client.Open;
    except
    Showmessage( 'Server nicht erreichbar' );
    Color := clBtnFace;
    exit;
    end;
  try
  if not OD.Execute then 
   begin
   if Client.Socket.Connected then Client.Close;
   Color := clBtnFace;   
   exit;
   end;
  Client.Socket.SendStream(  TFileStream.Create( OD.Filename, fmOpenRead or fmShareDenyWrite)  );
    except
    Showmessage( 'Stream versenden fehlgeschlagen' );
    if Client.Socket.Connected then Client.Close;
    Color := clBtnFace;
    exit;
    end;
if Client.Socket.Connected then Client.Close;
Color := clBtnFace;
end;

Dort dürften (denke ich mal) keine Fehler zu finden sein...


Zum Server (Empfänger) (steht auf stNonBlocking) (hier können sowohl FileStreams als auch MemoryStreams ankommen, beide werden aber in Dateien gespeichert !(soll so) )
ausblenden volle Höhe 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:
//fStream ist vom Typ TFileStream

//OnClientconnect
procedure TForm1.ServerClientConnect(Sender: TObject; Socket: TCustomWinSocket);
var DateiPfad: String;
    i: integer;
begin
if AnsiLastChar(Edit2.Text)<>'\' then Edit2.Text := Edit2.Text + '\';
i := 0;
repeat
  inc(i);//in Edit2 steht ein Pfad zum Ordner worin gespeichert werden soll (existiert)
  DateiPfad := Edit2.Text + Socket.RemoteAddress + '[' + IntToStr(i) + ']' + '.DATEI';
//Endung .DATEI, da man ja nicht weiß was man empfängt
until not FileExists( DateiPfad ); 
fStream := TFileStream.Create( DateiPfad, fmCreate or fmShareDenyWrite );
end;


//OnClientDisconnect
procedure TForm1.ServerClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
fStream.Free;
end;

//OnClientRead (so wird der Stream empfangen):
//Diese Procedure habe ich aus einem Tutorial... dabei bisschen umgeformt, aber größtenteils aus dem Tut.
procedure TForm1.ServerClientRead(Sender: TObject; Socket: TCustomWinSocket);
var iLen: Integer; // Länge des Streams
    Bfr: Pointer; // Puffer
begin
iLen := Socket.ReceiveLength; //empfangene Länge
GetMem(Bfr, iLen); // Puffer mit der Größe wird reserviert
  try
  Socket.ReceiveBuf(Bfr^, iLen); //empfangener Puffer
  FStream.Write(Bfr^, iLen);
    finally
    FreeMem(Bfr); // reservierter Puffer wird wieder geleert
    end;
end;


Fehler1: Beim Client erzeuge ich den Stream erst, nachdem schon verbunden wurde, aber das krieg ich wohl selber hin :D

eigentliche Fehler (2): Solange es nur 1 Sender (Client) ist, klappt es.. bei mehreren Sendern klappt es nur dann, wenn die Dateien sehr klein sind...
Sonst schafft der Server es einen Clienten zu blockieren und schmiert ab, wenn er mit dem "ersten" fertig ist, oder er versagt direkt...

Ich weiß, dass ich den ServerType auf stThreadBlocking stellen muss.. habe damit aber noch nie etwas zu tun gehabt und finde dazu auch keine Tutorials...

Wie kann ich einen funktionierenden stNonBlocking zu einem stThreadBlocking Server machen?

(Ich denke am Client muss ich nichts ändern?)

Freue mich auf eure Hilfe :)

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 23.06.13 21:48 
Du scheinst deine Clients gar nicht auf dem Server zu verwalten. Sprich du erstellst nur einen Stream und arbeitest damit. Wenn nun der nächste Client ankommst, erstellst du einfach einen neuen Stream, auch wenn fStream schon den Stream eines anderen Clients enthält und arbeitest dann damit. Im Disconnect gibst du dann diesen aktuellsten Stream frei, danach ist fStream ungültig. Wenn der zweite aber nun weiter etwas schickt oder disconnected, wird mit fStream gearbeitet, obwohl es freigegeben ist.

Das solltest du am Server auch seht gut mit Haltepunkten auf den drei Methoden nachvollziehen können...

Wenn mehrere Clients parallel verbinden können sollen, musst du die auch auseinander halten, jeweils eigene Streams erstellen und empfangene Daten dem jeweiligen Client und dessen Stream zuordnen.
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: So 23.06.13 22:57 
Wie kann ixh Clients denn unterscheiden, wenn sie dieselbe ip und remoteadress haben..?
Kann ich z.B den Index des connected sockets herausfinden?

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 23.06.13 23:23 
Du bekommst den Socket doch bei den Events immer als Parameter übergeben. Bei neueren Delphiversionen würde sich ein TDictionary anbieten um den Socket den Daten zuzuordnen, bei deinem Delphi 7 musst du dir was anderes einfallen lassen. Da bleibt wohl nur eine Liste mit einem Objekt mit den Daten zum Client und dem Socket und dann immer den passenden Socket darin suchen, wenn ein Event ankommt...

Für diesen Beitrag haben gedankt: IhopeonlyReader
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: So 23.06.13 23:41 
Ja, aber bei doppelconnections eines PCs habe ich 2 identische Clients, die etwas unterschiedlichliches schicken.,, ich kann sie also nicht auseinander halten und somit die streams nicht zuorden.. Deshalb fragte ich nach dem Index

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 24.06.13 07:13 
Wenn du wirklich 1:1 die selben Sockets hast, musst du das über ein Protokoll regeln...
Bist du dir dessen wirklich sicher?
Bau mal im OnConnect ein:
ausblenden Delphi-Quelltext
1:
ShowMessage(IntToHex(Integer(Pointer(Socket)), 8));					
Kommt da wirklich bei beiden dasselbe heraus, wenn die nacheinander verbinden und der erste noch verbunden ist?
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 24.06.13 13:18 
Natürlich :D die Speicheraddresse (Pointer) des Sockets :D
ich habe zu "netzwerk-mäßig" gedacht :D
denn RemoteAddress und RemoteHost sind ja gleich :D aber wenn man es genauer betrachtet liegt der Unterschied natürlich doch irgendwo :D

sorry, hätte ich auch selber darauf kommen können ^^ ich wollte direkt über die IP etc. das ganze einem Stream zuordnen

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 24.06.13 14:32 
Ich habe das ganze jetzt perfekt getrennt :)
dazu habe ich eine verkette Liste geschrieben (da die 2 Datei ja vor der 1 fertig sein kann) und darin wird dann alles verwaltet.. ist ein perfektes Vorbild für ein Chat zum zuordnen von Benutzername etc..

Hier der Code der selbstgeschrieben Unit:
ausblenden volle Höhe 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:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
unit uTSocketVerwaltung;

interface

uses Classes, SysUtils, ScktComp;

type
  TSocketStream = class( TObject )
  public
    next: TSocketStream;
    before: TSocketStream;
    fSocket: Cardinal; //Speicheraddresse vom Socket
    fStream: TFileStream;
  end;

  TSocketVerwaltung = class( TObject )
  private
    Anfang, Ende: TSocketStream;
    fAnzahl: Byte; //Maximal 255 gleichzeitig connected
    function Finde( pSocket: TCustomWinSocket ): TSocketStream;
  public
      property Anzahl: Byte read fAnzahl;
    constructor create; overload;
      procedure dazu( pSocket: TCustomWinSocket; DateiPfad: String );
      procedure loesche( pSocket: TCustomWinSocket );
      function GibStream( pSocket: TCustomWinSocket ): TFileStream;
    destructor destroy; override;
  end;


implementation

//---     ---     ---     private      ---     ---     ---
function TSocketVerwaltung.Finde( pSocket: TCustomWinSocket ): TSocketStream;
var pSA: Cardinal; //SpeicherAdresse
    pSS: TSocketStream; //SocketStream
    C: Byte;
begin
pSA := Cardinal( Pointer(pSocket) );
pSS := Anfang;
Result := nil;

For C:=1 to Anzahl do
  if (pSS.fSocket=pSA) then
    begin
    Result := pSS;
    break;
    end
  else
    begin
    pSS := pSS.next;
    end;
end;


//---     ---     ---     public      ---     ---     ---

constructor TSocketVerwaltung.create;
begin
inherited create;
fAnzahl := 0;
end;


procedure TSocketVerwaltung.dazu( pSocket: TCustomWinSocket; DateiPfad: String );
begin
if Assigned( Ende ) then
  begin
  Ende.next := TSocketStream.Create;
  Ende.next.before := Ende;
  Ende := Ende.next;
  end
else
  begin
  Anfang := TSocketStream.Create;
  Ende := Anfang;
  Ende.before := nil;
  end;
Ende.next := nil;
Ende.fSocket := Cardinal( Pointer(pSocket) );
Ende.fStream := TFileStream.Create( DateiPfad, fmCreate or fmShareDenyWrite );
inc( fAnzahl );
end;


procedure TSocketVerwaltung.loesche( pSocket: TCustomWinSocket );
var pSS: TSocketStream;
begin
pSS := Finde( pSocket );
if (pSS=nilthen exit;
if (pSS.before<>nilthen pSS.before.next := pSS.next;
if (pSS.next<>nilthen pSS.next.before := pSS.before;
if (pSS.fSocket=Anfang.fSocket) then Anfang := pSS.next;
if (pSS.fSocket=Ende.fSocket) then Ende := pSS.before;
pSS.fStream.Free;
pSS.Free;
dec( fAnzahl );
end;


function TSocketVerwaltung.GibStream( pSocket: TCustomWinSocket ): TFileStream;
begin
Result := Finde( pSocket ).fStream;
end;


destructor TSocketVerwaltung.destroy;
begin
inherited destroy;
end;
end.

ich geh ensprechend immer nach der Speicheradresse des Sockets...
abgeändert habe ich meinen ursprünglichen Quellcode kaum..
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
//aus der Globalen Variable Fstream wurde
SocketVerwaltung: TSocketVerwaltung;

//im ClientConnect aus FStream := TFileStream.create( DateiPfad );
SocketVerwaltung.dazu( Socket, DateiPfad ); 

//im ClientDisconnect aus FStream.Free;
SocketVerwaltung.loesche( Socket ); 

//und im ClientRead aus FStream.Write(Bfr^, iLen wurde nun  
SocketVerwaltung.GibStream( Socket ).Write(Bfr^, iLen);

Das ganze funktioniert wurderbar :) die Clients senden alle gleichzeitig und wie ich finde mit einer tollen Geschwindigkeit :)

Danke nocheinmal für den Hinweis auf die Speicheradressen-Sortierung.. ich hätte nach RemoteAddr. und RemoteHost geordnet :D

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 24.06.13 14:58 
Warum ist dein fSocket nicht gleich ein TCustomWinSocket? Die ganze Casterei kannst du dir sparen. ;-)

Zumal dein Code so auch nicht 64-Bit tauglich wäre, da Cardinal da falsch ist, da müsstest du NativeUInt nehmen.
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 24.06.13 16:23 
Aber 2 Klassen lassen sich nicht vergleichen, oder?

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 24.06.13 17:12 
Doch, das kannst du einfach vergleichen. Das ist intern ein Pointer auf das konkrete Objekt und den kannst du wie eine Zahl vergleichen.
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 24.06.13 18:30 
jo klappat :) danke

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!