Autor |
Beitrag |
Udontknow
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Di 03.08.04 17:45
Die Komponenten TSimpleUDPClient und TSimpleUDPServer in dieser Unit sind, ebenfalls wie SimpleTCP, Wrapperkomponenten der jeweiligen Indy-Pendants. Durch die Einführung eines Clientlesethreads und eines OnInput-Events wird die Handhabung der UDP-Komponenten vereinfacht.
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: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453:
| unit SimpleUDP;
interface
uses SysUtils, Classes, IdUDPClient, idUDPServer, IdUDPBase, idSocketHandle;
type TCommand=Integer;
const coData:TCommand=0;
const coDisconnect:TCommand=-1;
type TidSocketHandle=idSocketHandle.TidSocketHandle;
TSimpleUDPClient=class;
TProcessCommandEvent=procedure(Command:Integer; Stream:TStream) of object; THandleInputEvent=procedure(Sender:TObject;Stream:TStream) of object; TServerHandleInputEvent=procedure(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle) of object;
TClientThread=class(TThread) private function GetOnProcessCommand: TProcessCommandEvent; procedure SetOnProcessCommand(const Value: TProcessCommandEvent); function GetClient: TidUDPClient; procedure SetClient(const Value: TidUDPClient); protected FCommand:Integer; FStream:TMemoryStream; FClient:TidUDPClient; FOnProcessCommand:TProcessCommandEvent; procedure HandleProcessCommand; virtual; public procedure Execute; override; published property OnProcessCommand:TProcessCommandEvent read GetOnProcessCommand Write SetOnProcessCommand; property Client:TidUDPClient read GetClient write SetClient; end;
TSimpleUDPClient=class(TComponent) private FClient:TidUDPClient; FThread:TClientThread; FOnInput:THandleInputEvent; function GetOnInput: THandleInputEvent; procedure SetOnInput(const Value: THandleInputEvent); function GetActive: Boolean; function GetBufferSize: Integer; function GetHost: String; function GetPort: Integer; procedure SetActive(const Value: Boolean); procedure SetBufferSize(const Value: Integer); procedure SetHost(const Value: String); procedure SetPort(const Value: Integer); protected procedure ProcessCommand(Command:Integer; Stream:TStream); virtual; procedure SendCommand(Command:Integer; Stream:TStream); virtual; public constructor Create(AOwner:TComponent); override; destructor Destroy; override;
procedure SendStream(AStream:TStream);
published property OnInput:THandleInputEvent read GetOnInput write SetOnInput; property BufferSize:Integer read GetBufferSize write SetBufferSize; property Host:String read GetHost write SetHost; property Port:Integer read GetPort write SetPort; property Active:Boolean read GetActive write SetActive; end;
TSimpleUDPServer=class(TComponent) private FOnInput:TServerHandleInputEvent; function GetActive: Boolean; function GetBufferSize: Integer; function GetOnInput: TServerHandleInputEvent; function GetPort: Integer; procedure SetActive(const Value: Boolean); procedure SetBufferSize(const Value: Integer); procedure SetOnInput(const Value: TServerHandleInputEvent); procedure SetPort(const Value: Integer); procedure UDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle); protected FServer:TidUDPServer; procedure ProcessCommand(Binding:TIdSocketHandle; Command:Integer; Stream:TStream); virtual; procedure SendCommand(PeerIP:String;PeerPort:Integer;Command:Integer; Stream:TStream); virtual; public constructor Create(AOwner:TComponent); override; destructor Destroy; override; published property OnInput:TServerHandleInputEvent read GetOnInput write SetOnInput; property BufferSize:Integer read GetBufferSize write SetBufferSize; property Port:Integer read GetPort write SetPort; property Active:Boolean read GetActive write SetActive;
end;
procedure Register;
implementation
procedure Register; begin RegisterComponents('Simple Network',[TSimpleUDPClient,TSimpleUDPServer]); end;
constructor TSimpleUDPClient.Create(AOwner: TComponent); begin inherited; FClient:=TidUDPClient.Create(Self); FThread:=TClientThread.Create(True); FThread.FClient:=FClient; FThread.FOnProcessCommand:=ProcessCommand; FThread.Resume; end;
destructor TSimpleUDPClient.Destroy; begin FThread.Free; inherited; end;
procedure TClientThread.Execute; var BytesRead, BytesToRead:Integer; var Ptr:Pointer; begin Ptr:=NIL; Getmem(Ptr,FClient.BufferSize); try While not Terminated do begin if (not FClient.Active) then begin sleep(40); Continue; end;
try BytesRead:=FClient.ReceiveBuffer(Ptr^,FClient.BufferSize,20);
if BytesRead>0 then begin FCommand:=Integer(Ptr^); BytesToRead:=Integer(Pointer(Integer(Ptr)+4)^); if BytestoRead>FClient.BufferSize-4 then raise Exception.Create('data size exceeds packet size!');
FStream:=TMemoryStream.Create; try FStream.Size:=BytesToRead; Move(Pointer(Integer(Ptr)+8)^,FStream.Memory^,BytesToRead); FStream.Position:=0; Synchronize(HandleProcessCommand); finally FStream.Free; end; end;
except end; end; finally FreeMem(Ptr); end; end;
function TClientThread.GetClient: TidUDPClient; begin Result:=FClient; end;
function TClientThread.GetOnProcessCommand: TProcessCommandEvent; begin Result:=FOnProcessCommand; end;
procedure TClientThread.HandleProcessCommand; begin if Assigned(FOnProcessCommand) then FOnProcessCommand(FCommand,FStream); end;
procedure TClientThread.SetClient(const Value: TidUDPClient); begin FClient:=Value; end;
procedure TClientThread.SetOnProcessCommand( const Value: TProcessCommandEvent); begin FOnProcessCommand:=Value; end;
function TSimpleUDPClient.GetActive: Boolean; begin Result:=FClient.Active; end;
function TSimpleUDPClient.GetBufferSize: Integer; begin Result:=FClient.BufferSize; end;
function TSimpleUDPClient.GetHost: String; begin Result:=FClient.Host; end;
function TSimpleUDPClient.GetOnInput: THandleInputEvent; begin Result:=FOnInput; end;
function TSimpleUDPClient.GetPort: Integer; begin Result:=FClient.Port; end;
procedure TSimpleUDPClient.ProcessCommand(Command: Integer; Stream: TStream); begin if (Command=coData) and (Assigned(FOnInput)) then FOnInput(Self,Stream); end;
procedure TSimpleUDPClient.SendCommand(Command: Integer; Stream: TStream); var BufferPtr:Pointer; begin if Stream.Size>BufferSize-8 then raise Exception.Create('Data size exceeds buffer size!'); Stream.Position:=0; Getmem(BufferPtr,Stream.Size+8); try Integer(BufferPtr^):=Command; Integer(Pointer(Integer(BufferPtr)+4)^):=Stream.Size; Stream.ReadBuffer(Pointer(Integer(BufferPtr)+8)^,Stream.Size); FClient.SendBuffer(BufferPtr^,Stream.Size+8); finally FreeMem(BufferPtr); end; end;
procedure TSimpleUDPClient.SendStream(AStream: TStream); begin SendCommand(CoData,AStream); end;
procedure TSimpleUDPClient.SetActive(const Value: Boolean); begin FClient.Active:=Value; end;
procedure TSimpleUDPClient.SetBufferSize(const Value: Integer); begin FClient.BufferSize:=Value; end;
procedure TSimpleUDPClient.SetHost(const Value: String); begin FClient.Host:=Value; end;
procedure TSimpleUDPClient.SetOnInput(const Value: THandleInputEvent); begin FOnInput:=Value; end;
procedure TSimpleUDPClient.SetPort(const Value: Integer); begin FClient.Port:=Value; end;
constructor TSimpleUDPServer.Create(AOwner: TComponent); begin inherited; FServer:=TidUdpServer.Create(Self); FServer.OnUDPRead:=UDPRead; end;
destructor TSimpleUDPServer.Destroy; begin FServer.Free; inherited; end;
function TSimpleUDPServer.GetActive: Boolean; begin Result:=FServer.Active; end;
function TSimpleUDPServer.GetBufferSize: Integer; begin Result:=FServer.BufferSize; end;
function TSimpleUDPServer.GetOnInput: TServerHandleInputEvent; begin Result:=FOnInput; end;
function TSimpleUDPServer.GetPort: Integer; begin Result:=FServer.DefaultPort; end;
procedure TSimpleUDPServer.ProcessCommand(Binding: TIdSocketHandle; Command: Integer; Stream: TStream); begin if (Command=coData) and (Assigned(FOnInput)) then FOnInput(Self,Stream,Binding); end;
procedure TSimpleUDPServer.SendCommand(PeerIP: String; PeerPort, Command: Integer; Stream: TStream); var BufferPtr:Pointer; begin if Stream.Size>BufferSize-8 then raise Exception.Create('Data size exceeds buffer size!'); Stream.Position:=0; Getmem(BufferPtr,Stream.Size+8); try Integer(BufferPtr^):=Command; Integer(Pointer(Integer(BufferPtr)+4)^):=Stream.Size; Stream.ReadBuffer(Pointer(Integer(BufferPtr)+8)^,Stream.Size); FServer.SendBuffer(PeerIP,PeerPort,BufferPtr^,Stream.Size+8); finally FreeMem(BufferPtr); end; end;
procedure TSimpleUDPServer.SetActive(const Value: Boolean); begin FServer.Active:=Value; end;
procedure TSimpleUDPServer.SetBufferSize(const Value: Integer); begin FServer.Buffersize:=Value; end;
procedure TSimpleUDPServer.SetOnInput( const Value: TServerHandleInputEvent); begin FOnInput:=Value; end;
procedure TSimpleUDPServer.SetPort(const Value: Integer); begin FServer.DefaultPort:=Value; end;
procedure TSimpleUDPServer.UDPRead(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle); var BytesToRead:Integer; var Command:integer; var Stream:TMemoryStream; begin AData.ReadBuffer(Command,SizeOf(Command)); AData.ReadBuffer(BytesToRead,SizeOf(BytesToRead));
if BytesToRead<>AData.Size-8 then raise Exception.Create('data size does not represent packet size!');
Stream:=TMemoryStream.Create; try Stream.CopyFrom(AData,BytesToRead); Stream.Position:=0; ProcessCommand(ABinding,Command,Stream); finally Stream.Free; end; end;
end. |
Zuletzt bearbeitet von Udontknow am Mi 24.11.04 09:54, insgesamt 2-mal bearbeitet
|
|
matze
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: Mi 04.08.04 08:09
wow cool. also mich muss schon mal sagen: diese warapper klasse von dir sind echt gut, dadurch kann man sich bei kleinen projekten einen haufen zeit sparen !
_________________ In the beginning was the word.
And the word was content-type: text/plain.
|
|
Udontknow
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Mi 04.08.04 08:52
Danke.
Cu,
Udontknow
|
|
Elite
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 04.10.04 12:44
Hab ne generelle Frage zum Installieren der Komponenten:
Ist es richtig, wenn ich
1. Quelltext als neue Unit speichere?
2. Komponente -> Koponente installieren
3. in neues Package
Oder sollte ich ein vorhandenes Package nehmen? Kann ich die compilierte exe trotz zusätzlichem Package weiter geben?
|
|
BenBE
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mo 04.10.04 13:10
Ist so richti.
In welchem Package du die Unit speicherst ist egal, da das nur für Delphi* interessant ist.
* Außer du nutzt Laufziet-Packages, da du in diesem Fall das Laufzeitpackage weitergeben müsstest.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Elite
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 04.10.04 15:38
Sooo,
äußerlich gefallen mir die Kompos sehr
Sieht alles sehr übersichtlich und einfach aus mit Stream senden und empfangen.
Nur leider bekomme ich das gute Stück nicht zum funktionieren. Hiermein bisheriger Code, in dem einfach 2 integers vom Client zum Server geschickt werden (sollen):
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:
| procedure TForm1.Sende2IntegersClick(Sender: TObject); var a,b: integer; begin a:=strtoint(Edit1.Text); b:=strtoint(Edit2.Text); Stream := TMemoryStream.Create; try With Stream do begin Write(a,4); Write(b,4); end; UdpClient1.SendStream(Stream); finally Stream.Free; end; end;
procedure TForm1.UDPServer1Input(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle); var a,b:integer; begin with stream do begin read(a,4); read(b,4); end; Edit3.Text := inttostr(a); Edit4.Text := inttostr(b); end; |
Bei beiden ist Active auf true und beim Client habe ich als IP 127.0.0.1 (müsste localhost sein) eingegeben. Auch der Port stimmt überein. Es wird keine Exception ausgelöst, sondern die Daten von Edit1 und 2 werden einfach nicht nach Edi3 und 4 übernommen.
Was mache ich falsch?
Edit:Fehler gefunden!
Hab in der zweiten Prozedur Stream(global) statt AData verwendet.
Zuletzt bearbeitet von Elite am Mo 04.10.04 15:56, insgesamt 1-mal bearbeitet
|
|
Udontknow
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Mo 04.10.04 15:54
Wie wäre es, wenn du "AData" anstatt die globale Variable "Stream" benutzt?
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.UDPServer1Input(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle); var a,b:integer; begin with Adata do begin read(a,4); read(b,4); end; Edit3.Text := inttostr(a); Edit4.Text := inttostr(b); end; |
Das ist einer der Gründe, warum man nie unnötigerweise globale Variablen anlegen sollte, packe die Stream-Deklaration in die Sende-Prozedur.
Cu,
Udontknow
|
|
Elite
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 04.10.04 15:58
lol, ich sollte mir angewöhnen die Seite neu zu laden, bevor ich poste ^^
Aber trotzdem schönen Dank. Find die Kompos echt klasse. Damit kann ich ja praktisch jede x-beliebige Netzwerkkommunikation einfach realisieren.
*UDontKnow ganz dick lobt*
|
|
Udontknow
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Mo 04.10.04 16:04
Danke fürs Lob.
Cu,
Udontknow
|
|
Elite
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 04.10.04 16:46
kann ich denn damit auch broadcasts senden oder muss ich erst herausfinden, was die netzwerkspezifische broadcast-ip ist?
|
|
Udontknow
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Mo 04.10.04 17:08
Die Komponenten richten sich aus an dem typischen Client-Server-Betrieb, da UDP-Broadcasting im Internet nichts bringt.
Schau dir doch auch mal die SimpleNetworkGame-Unit an, dort habe ich die TCP- und die UDP-Komponenten miteinander verflochten, sodaß über die Verbindungsliste des Servers ein "Broadcast" möglich wäre.
Cu,
Udontknow
|
|
Elite
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 04.10.04 17:16
Ich will sie aber für lan nutzen, weshalb Broadcast mich durchaus weiter bringen würde.
Habe eben versucht mit einer normalen TidudpClient einen Integer zu senden, der dann von deinem SimpleUDPServer empfangen werden sollte. Hat nicht hingehauen? Funktionieren sollte es schon oder?
|
|
Udontknow
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Mo 04.10.04 17:34
Die SimpleUDP-Komponenten erwarten grundsätzlich folgenden Paket-Aufbau:
1. Kommando vom Typ Integer. In der eigentlich UDP-Komponente wird nur coData (0) weiterverarbeitet, durch Übersteuerung von ProcessCommand kann man weitere Befehle implementieren.
2. Anzahl an Bytes der folgenden Datenmenge im Paket als Integer.
3. Die eigentlichen Daten.
Wenn du also ein Integer sendest, muß das Paket aus 12 Byte bestehen: [codata,4,Zahl]
Cu,
Udontknow
|
|
Florian H
Beiträge: 52
Win XP
D6 Pro
|
Verfasst: Do 18.11.04 17:56
hm, wenn ich die Unit installieren will, kommt die Meldung Zitat: | [Fataler Fehler] SimpleUDP.pas(51): 'Never-build' Package 'IndySystem60' muß neu compiliert werden |
und wie mache ich das??
|
|
Udontknow
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Do 18.11.04 18:10
Hallo!
Tut mir leid, aber die Meldung habe ich so noch nie gesehen. Ich habe die Komponenten mit Delphi 7 entwickelt, aber wenn sich die Schnittstellen nicht verändert haben, sollte das auch klappen...
Edit : So ein Paket habe ich bei mir gar nicht, evtl musst du mal deine Indy-Komponenten updaten.
www.indyproject.org/...load/Files/Indy9.iwp
Edit2: Unbedingt den Hinweis "Delphi 6 & 7 Specific Notes" beachten!
Cu,
Udontknow
|
|
Florian H
Beiträge: 52
Win XP
D6 Pro
|
Verfasst: Do 18.11.04 19:33
hi,
ansich hab ich die INDY's bei meiner Delphi6-Installation vor ein paar Wochen extra weggelassen und dafür die aktuelle 9er- (oder doch 10er?!?)-Version der INDYs genommen... egal, ich versuchs nochmal mit V9.18
|
|
Stefan-W
Beiträge: 475
Win 7 SP1
D2005 PE
|
Verfasst: Di 23.11.04 18:28
Hi
erstmal großes Lob, die Unit gefällt mir sehr...
nur leider bekomm ich immer ein Fehler und ich weis nicht woran es liegt (bin nicht der Schlauste auf dem Gebiet)
Delphi 7 hat folgendes geschrieben: | [Fehler] Unit1.pas(25): Undefinierter Bezeichner: 'TIdSocketHandle' |
in der Zeile steht das hier
Zitat: | Procedure SimpleUDPServer1Input(Sender: TObject; AData: TStream; ABinding: TIdSocketHandle); |
ich hoffe mir kann noch geholfen werden...
Schon mal danke
EDIT: Ich habs gefunden! Mir fehlt die idSocketHandle.pas oder idSocketHandle.dcu, nun brauch ich nur noch ne Lösung...
Edit2: Also die Datei hab ich doch aber das Problem besteht weiter...
Tschau
|
|
Udontknow
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Di 23.11.04 18:44
Hmmm... Hast du den Bibliothekspfad um das Indy-Source-Verzeichnis ergänzt? Siehe Tools\Umgebungsoptionen\Bibliothek.
Cu,
Udontknow
|
|
Raphael O.
Beiträge: 1596
VS 2013
|
Verfasst: Di 23.11.04 18:44
die Indy-DCU-Dateien müssen in einem Ordner liegen, der auch als Suchpfad eingegeben ist...
|
|
Stefan-W
Beiträge: 475
Win 7 SP1
D2005 PE
|
Verfasst: Di 23.11.04 18:48
ist alles, hab ich schon kontrolliert.
kann es an der Version liegen? Hab 9.0.14
|
|