![]() |
AW: Socket-Verbindung herstellen ohne zu blockieren
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Tipp: "ICS Overbyte" kannst du in neueren Delphis direkt über dein Delphi, dort über "Tools > GetItPackageManager, ICS Overbyte" installieren. Mit Overbyte ist alles Ereignis gesteuert. Du kannst zum Beispiel direkt auf OnChangeState des Sockets reagieren: Wenn dir via das Ereignis TWSocket.OnChangeState signalisiert wird, dass dein Socket neu geschlossen ist (wsClosed), kannst du den Wiederaufbau einleiten. Beispiel (Code unten). Drei Sockets: ListenSocket, SocketB und SocketA. Ziel: Aufbau einer Verbindung SocketA <-> SocketB. Beim Starten der App geht der ListenSocket auf wsListening. (FormCreate) Drück den Button „Verbinde“. SocketA leitet den Verbindungsaufbau zu ListenSocket ein (Verbinde). ListenSocket: Das Ereignis OnSessionAvailable wird ausgelöst (ListenSocketSessionAvailable). ListenSocket akzeptiert die Verbindung (Accept) und SocketB übernimmt diese (Dup). SocketA und SocketB sind nun miteinander verbunden. Zweites Ziel: Wiederaufbau der Leitung, falls SocketA.SocketState = wsClosed: Drück den Button „Schliessen“. SocketA oder SocketB werden geschlossen. Via das Ereignis OnChangeState (SocketAChangeState) werden Änderungen des SocketStates signalisiert. Sollte der SocketState von SocketA neu wsClosed sein, leiten wir den Wiederaufbau der Verbindung SocketA -> (ListenSocket ->) Socket B ein. Im Memo werden alle Änderungen der SocketStates angezeigt. Drittes Ziel: Sende einen String von A nach B. Mittels SocketA.SendStr( s ) versendest du einen String s. Im Ereignis OnDataAvailable von SocketB wird der Empfang von Daten angezeigt. Die Daten können zum Beispiel mit SocketB.ReceiveStr ausgelesen werden. [ In der Praxis kann es hilfreich sein, periodisch ein „Ping-Paket“ über die aufgebaute Leitung zu senden und die Verbindung neu aufzubauen, wenn das Paket „zu lange“ nicht quittiert wird. Wahrscheinlich würdest du zu sendende Daten in einen Buffer schreiben und erst dann löschen, wenn die Gegenstelle den Empfang der Daten bestätigt hat.]
Delphi-Quellcode:
unit Unit38;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, OverbyteIcsWndControl, OverbyteIcsWSocket, Vcl.StdCtrls; const WM_MEINEMELDUNG = WM_APP + 1; type TForm38 = class(TForm) SocketA: TWSocket; ListenSocket: TWSocket; SocketB: TWSocket; VerbindeButton: TButton; SchliessenButton: TButton; Memo1: TMemo; SendeString: TButton; procedure FormCreate(Sender: TObject); procedure VerbindeButtonClick(Sender: TObject); procedure ListenSocketSessionAvailable(Sender: TObject; ErrCode: Word); procedure SocketAChangeState(Sender: TObject; OldState, NewState: TSocketState); procedure SchliessenButtonClick(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure SendeStringClick(Sender: TObject); procedure SocketBDataAvailable(Sender: TObject; ErrCode: Word); private { Private-Deklarationen } procedure Machetwas(var Message: TMessage); message WM_MEINEMELDUNG; public { Public-Deklarationen } procedure Verbinde; end; var Form38: TForm38; implementation {$R *.dfm} uses System.TypInfo; var appschliesst : boolean = false; function socketstr( hss : TSocketState ) : string; begin { Wert von hss in String umwandeln } Result := GetEnumName(typeinfo(TSocketState),ord(hss)); end; procedure TForm38.Machetwas(var Message: TMessage); begin case Message.WParam of 0 : begin { Störung simulieren: SocketA oder Gegenstelle SocketB schliessen } Memo1.Lines.Add('Entweder SocketA oder SocketB schliessen'); case random(2) of 0: SocketA.Close; 1: SocketB.Close; end; end; { SocketA verbindet neu mit der Gegenstelle } 1 : Verbinde; end; end; procedure TForm38.SchliessenButtonClick(Sender: TObject); begin PostMessage( Handle, WM_MEINEMELDUNG, 0, 0 ); end; procedure TForm38.VerbindeButtonClick(Sender: TObject); begin Verbinde; end; { ListenSocket geht in den SocketState wsListening über: } procedure TForm38.FormCreate(Sender: TObject); begin ListenSocket.Addr := '0.0.0.0'; ListenSocket.Port := '7001'; ListenSocket.Proto := 'tcp'; ListenSocket.Listen; ListenSocket.OnChangeState := SocketAChangeState; SocketA.OnChangeState := SocketAChangeState; SocketB.OnChangeState := SocketAChangeState; ListenSocket.OnSessionAvailable := ListenSocketSessionAvailable; SocketB.OnDataAvailable := SocketBDataAvailable; end; { SocketA soll mit ListenSocket verbinden: } procedure TForm38.Verbinde; begin Memo1.Lines.Add('SocketA Verbindungsaufbau'); SocketA.Close; SocketA.Addr := '127.0.0.1'; SocketA.proto := 'tcp'; SocketA.Port := '7001'; SocketA.Connect; end; { OnSessionAvailable: ListenSocket akzeptiert die Verbindung, SocketB übernimmt (Dup) - SocketA und SocketB sind miteinander verbunden } procedure TForm38.ListenSocketSessionAvailable(Sender: TObject; ErrCode: Word); var h : THandle; begin h := ListenSocket.Accept; SocketB.Dup( h ); end; { ChangeState: Änderung SocketState } procedure TForm38.SocketAChangeState(Sender: TObject; OldState, NewState: TSocketState); begin if appschliesst then begin if ( SocketA.State = wsclosed ) and ( SocketB.State = wsClosed ) then close; end else begin Memo1.Lines.Add( (Sender as TWSocket).Name + ' ' + socketstr(OldState) + '->' + socketstr(NewState) ); if ( Sender = SocketA ) then if ( OldState = wsConnected ) and ( NewState = wsClosed ) then PostMessage( Handle, WM_MEINEMELDUNG, 1, 0 ); end; end; { Beispiel: SocketA sendet einen String an SocketB } procedure TForm38.SendeStringClick(Sender: TObject); begin if SocketA.State = wsConnected then SocketA.SendStr( Memo1.Text ); end; { SockezB empfängt den String} procedure TForm38.SocketBDataAvailable(Sender: TObject; ErrCode: Word); var empfangen : string; begin empfangen := SocketB.ReceiveStr; if empfangen <> '' then ShowMessage( empfangen ); end; { Die App soll geschlossen werden... Wenn SocketA oder SocketB nicht geschlossen sind => canclose:= false => Im SocketAChangeState wird Close aufgerufen, sobald SocketA und SocketB geschlossen sind } procedure TForm38.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin {.....} if canclose then begin appschliesst := true; ListenSocket.Close; SocketA.CloseDelayed; SocketB.CloseDelayed; canclose := ( SocketA.State = wsclosed ) and ( SocketB.State = wsClosed ); end; end; end. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:20 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