Entwickler-Ecke
Open Source Units - "SimpleUDP" (Indy-Wrapper) *** Version 1.0.0.1 ***
Udontknow - Di 03.08.04 17:45
Titel: "SimpleUDP" (Indy-Wrapper) *** Version 1.0.0.1 ***
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.
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: 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. |
matze - 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 !
Udontknow - Mi 04.08.04 08:52
Danke. :)
Cu,
Udontknow
Delete - 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 - 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.
Delete - 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):
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:
| 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.
Udontknow - Mo 04.10.04 15:54
Wie wäre es, wenn du "AData" anstatt die globale Variable "Stream" benutzt? :wink: :)
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
Delete - 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 - Mo 04.10.04 16:04
Danke fürs Lob. :D
Cu,
Udontknow
Delete - 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 - 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
Delete - 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 - 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 - 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 - 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... :nixweiss:
Edit : So ein Paket habe ich bei mir gar nicht, evtl musst du mal deine Indy-Komponenten updaten.
http://www.indyproject.org/download/Files/Indy9.iwp
Edit2: :!: Unbedingt den Hinweis "Delphi 6 & 7 Specific Notes" beachten!
Cu,
Udontknow
Florian H - 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 - 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... :wink:
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 - 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. - Di 23.11.04 18:44
die Indy-DCU-Dateien müssen in einem Ordner liegen, der auch als Suchpfad eingegeben ist...
Stefan-W - Di 23.11.04 18:48
ist alles, hab ich schon kontrolliert.
kann es an der Version liegen? Hab 9.0.14
Raphael O. - Di 23.11.04 18:49
die läuft hier wunderbar...
besteht das problem bei jeder indy-anwendung, oder nur im zusammenhang mit der unit hier
Stefan-W - Di 23.11.04 18:52
KA
ist das erste mal das ich sowas mach weil mir das immer zu kompliziert aussah... :?
EDIT: ich hab jetzt mal das 9.0.18 drauf gemacht
EDIT: Gut ich habs! Ich hab die Datei (idSocketHandle.dcu) noch mit in mein Proc eingebunden und nun geht alles, erstmal soweit...
THX & CU
Udontknow - Mi 24.11.04 09:58
Ahso, das war das Problem. Gut, ich habe eine neue Version gepostet, die den Typ TidSocketHandle in der Unit weiterdeklariert, sodaß das Einfügen der Unit idSocketHandle nicht mehr vonnöten ist. :)
Cu,
Udontknow
phogl - Mi 12.01.05 16:11
Also die compos find ich echt super, dickes lob, unter D7 hab ich die zum laufen bekommen aber unter D2k5 bekomm ich das einfach net gebacken *trottelist*
Wär nett wenn mir das jemand schreitt für schritt erklären würde. Danke schonmal in Vorraus!
Udontknow - Mi 12.01.05 17:08
Hallo!
Unter D2005 sind die Indy-10-Komponenten dabei, die SimpleTCP-Sachen benötigen jedoch Indy-9. Ich werde mal schauen, daß ich die portiere. :)
Cu,
Udontknow
phogl - Do 13.01.05 13:03
Aso, ok, wär ziemlich geil, auch wenn sich Delphi mit 2005 immer näher an M$ ranrückt, was ich nicht so doll mag, aber wir wolln hier ja nicht offtopic werden nä?!...
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!