Autor |
Beitrag |
IhopeonlyReader
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: 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):
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) )
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:
| 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); DateiPfad := Edit2.Text + Socket.RemoteAddress + '[' + IntToStr(i) + ']' + '.DATEI'; until not FileExists( DateiPfad ); fStream := TFileStream.Create( DateiPfad, fmCreate or fmShareDenyWrite ); end;
procedure TForm1.ServerClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin fStream.Free; end;
procedure TForm1.ServerClientRead(Sender: TObject; Socket: TCustomWinSocket); var iLen: Integer; Bfr: Pointer; begin iLen := Socket.ReceiveLength; GetMem(Bfr, iLen); try Socket.ReceiveBuf(Bfr^, iLen); FStream.Write(Bfr^, iLen); finally FreeMem(Bfr); end; end; |
Fehler1: Beim Client erzeuge ich den Stream erst, nachdem schon verbunden wurde, aber das krieg ich wohl selber hin
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
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: 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
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: 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
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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: 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
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: Mo 24.06.13 13:18
Natürlich die Speicheraddresse (Pointer) des Sockets
ich habe zu "netzwerk-mäßig" gedacht
denn RemoteAddress und RemoteHost sind ja gleich aber wenn man es genauer betrachtet liegt der Unterschied natürlich doch irgendwo
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
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
IhopeonlyReader
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: 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:
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; fStream: TFileStream; end;
TSocketVerwaltung = class( TObject ) private Anfang, Ende: TSocketStream; fAnzahl: Byte; 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
function TSocketVerwaltung.Finde( pSocket: TCustomWinSocket ): TSocketStream; var pSA: Cardinal; pSS: TSocketStream; 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;
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=nil) then exit; if (pSS.before<>nil) then pSS.before.next := pSS.next; if (pSS.next<>nil) then 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..
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| SocketVerwaltung: TSocketVerwaltung;
SocketVerwaltung.dazu( Socket, DateiPfad );
SocketVerwaltung.loesche( Socket );
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
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: Mo 24.06.13 16:23
Aber 2 Klassen lassen sich nicht vergleichen, oder?
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: Mo 24.06.13 18:30
jo klappat danke
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
|