Entwickler-Ecke
Internet / Netzwerk - Verbindung zwischen 2 Progs im Netzwerk/Internet
Fabian W. - Mi 05.10.05 16:25
Titel: Verbindung zwischen 2 Progs im Netzwerk/Internet
Hallo,
ich suche nach möglichkeiten, wie ich eine Verbindung übers Internet / Lokalnetzwerk herstelle, mit der ich Dateien von Prog 1 nach Prog 2 und von 2 nach 1 schicken kann.
1)Ist das mit einer Technik möglich oder muss ich da wieder zwischen Netzwerk und INternet unterscheiden?
2)Ich hab wirklich keine Ahnung von der Materie, habt also bitte Gedult mit mir und schlagt mir net nur Facheusdrücke um die Ohr'n ;-).
jakobwenzel - Mi 05.10.05 16:40
zu 1) Ich hab mal ein Chat-Programm mit den Indys fürs lokale Netzwerk geschrieben, das läuft auch über internet.
Fabian W. - Mi 05.10.05 16:43
Kannst du mir dann sagen wie ich die Indys einsetzen muss, damit das bei mir klappt?
Und vorallem: Wie bekomme ich so ne Verbindung zum laufen, was müsste der Benutzer eingeben usw..., wenn alles fertig is?
jakobwenzel - Mi 05.10.05 16:49
Ich habs über TidTCPServer und TidTCPClient gemacht. Bei mir ist es so, dass zuerst ausgewählt werden muss, ob das Prog als Server oder Client gestartet werden soll, außerdem muss bei Client noch die IP des Servers eingegeben werden. Der Client liest über einen Timer alle 0,5 s neue Nachrichten aus, der Server verschickt die Nachrichten, die vom Server kommen an alle Clients. (Brauchst du bei einem Chat für 2 natürlich nicht) Irgendwo gab es da aber auch schon ein Beispiel, ich weiß nur nicht wo.
Fabian W. - Mi 05.10.05 17:23
Das Prog soll Schachspielen übers Internet / Netzwerk ermöglichen, ich bracuh also auch nur nen Server und nen Client. Kannst du vlt. etwas BspCode posten??
jakobwenzel - Mi 05.10.05 17:52
Also ich poste mal was von meinem Code, die speziellen Sachen für den Chat hab ich mal rausgenommen, damit es übersichtlich bleibt.
Bei meinem Chat sind die Nachrichten immer wie folgt aufgebaut: Erst ein auf drei Buchtaben bestehendes Kommando, wie MSG (Message -> Nachricht), dann ein Leerzeichen, und dann der Text der Nachricht. Die Kommandos habe ich in String-Konstanten gespeichert.
Beispiel-Nachricht:
Also, das ist die OnExecute-Methode des TidTCPServers:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure TForm2.IdTCPServerExecute(AContext: TIdContext); var lRow, lCmd,lother:String; nick,nachricht,command:String; i:Integer; begin lRow:=Trim(AContext.Connection.IOHandler.ReadLn); lCmd:=lRow; SetLength(lCmd,4); If AnsiSameText(lCmd, Join) Then begin end else if AnsiSameText(lCmd, Msg) then begin end else if AnsiSameText(lCmd, Leave) then begin end; end; |
Wenn der Server eine Nachricht an den Client schickt, kann diese Prozedur benutzt werden. (In diesem Fall ist halt nur ein Client vorhanden, ist aber eigentlich egal.)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm2.SendToAllClients(s:String); var list:TList; i:Integer; sCmd:String; begin List := idTcpServer.Contexts.LockList; for i:=0 to List.Count-1 do tIdContext(List.Items[i]).Connection.IOHandler.WriteLn(s); IdTCPServer.Contexts.UnlockList; end; |
Hierbei wird der Parameter s an alle Clients geschickt.
Auslese-Prozedur für den Client:
(Timer1 ist auf einen Intervall von 500ms eingestellt und standardmäßig deaktiviert)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| procedure TForm2.Timer1Timer(Sender: TObject); var lCmd,lRow,user:String; i:Integer; begin try lRow:=IdIOHandlerStack.ReadLn('',5); if lRow<>'' then begin lCmd:=lRow; SetLength(lCmd,4); if AnsiSameText(lCmd, cls) then begin Timer1.Enabled:=false; end else end; except IdTCPClient.Disconnect; MessageDlg('Verbindungsabbruch.',mtError,[mbOk],0); Timer1.Enabled:=false; end; end; |
Und zum Schluss noch das Verbinden. (Ich hoffe, die Namen der Edit-Felder sind für dich verständlich)
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:
| procedure TForm2.ButtonLogInClick(Sender: TObject); var str,strn:String; i:Integer; begin (Sender as TButton).Caption:='Verbinde...'; try try if RadioGroupType.ItemIndex=0 Then begin IdTCPServer.Active:=true; end else begin str:=MaskEditHostIp.Text; strn:=''; for i:=1 to Length(str) do if str[i]<>' 'then strn:=strn+str[i]; IdTCPClient.Host:=strn; IdTCPClient.Connect; IdIOHandlerStack.WriteLn(Join+EditNick.Text); Timer1.Enabled:=true; end; except on E: EidSocketError do begin case E.LastError of 10061: str:='Auf der Angegebenen Ip läuft unter dem angegebenen Port kein Server!'; 10060: str:='Die angegebene IP exisitiert nicht.'; else str:='Konnte nicht verbinden.' end; MessageDlg(str,mtError,[mbOK],0); end; end; finally if RadioGroupType.Enabled then (Sender as TButton).Caption:='Einloggen'; end; end; |
Das waren die wichtigsten Code-Ausschnitte, falls du dir alles noch anschauen willst, ich habe das Projekt als zip angehängt.
P.S.: Du brauchst die Indys in der Version 10, damit alles ohne Änderungen ausgeführt werden kann.
Udontknow - Mi 05.10.05 18:38
Ich verweise noch mal auf diesen
Thread [
http://www.delphi-forum.de/viewtopic.php?t=47667&highlight=], indem ich angemerkt hatte, daß man nicht ohne weiteres im Server-OnExecute-Ereignis alles machen kann, was man will, man befindet sich nämlich dort nicht im VCL-Hauptthread.
Wenn du sowohl Client als auch Server entwickelst, kannst du dich ja mal mit den
SIMPLETCP-Komponenten beschäftigen, die ich geschrieben habe; Diese lösen die Thread-Problematik halbwegs elegant, allerdings musst du dich dann mit der Benutzung von Streams zurechtfinden.
Cu,
Udontknow
GTA-Place - Mi 05.10.05 18:39
Was für ein Zufall:
Ich habe gerade hier in der Libary ein Tutorial zum Thema erstellt.
Und die Methode aus meinem Tutorial ist kürzer als die Methode von Jakob oben.
Fabian W. - Do 06.10.05 17:26
Udontknow hat folgendes geschrieben: |
Ich verweise noch mal auf diesen Thread [http://www.delphi-forum.de/viewtopic.php?t=47667&highlight=], indem ich angemerkt hatte, daß man nicht ohne weiteres im Server-OnExecute-Ereignis alles machen kann, was man will, man befindet sich nämlich dort nicht im VCL-Hauptthread.
Wenn du sowohl Client als auch Server entwickelst, kannst du dich ja mal mit den SIMPLETCP-Komponenten beschäftigen, die ich geschrieben habe; Diese lösen die Thread-Problematik halbwegs elegant, allerdings musst du dich dann mit der Benutzung von Streams zurechtfinden.
Cu,
Udontknow |
Streams = Fehlanzeige, noxch nie was mit gemacht.
@jakobwenzel: Könntest du mir evtl. zeigen, wie ich mit deiner Methode Dateien verschicke, ich hab mir deine mal angekuckt und würds gerne mit der machen, so es denn geht.
@Fabian Gärtner: Sei mir net bös, aber ich würde zuerst gerne die von jakob versuchen, ich komme später auf deinen Vorschlag zurück, falls die andere net geht ;-)
jakobwenzel - Fr 07.10.05 19:01
weiß ich nicht so genau, aber wozu musst du denn Dateien versenden?
Dateien versenden würde ungefähr so ablaufen, dass erst eine Art Ankündigung gesendet wird, dass jetzt eine Datei kommt, und dann wird die Datei gesendet. Aber an Streams wirst du nicht vorbeikommen, da die Datei (Glaube ich) als Stream empfangen werden muss.
Fabian W. - Fr 07.10.05 21:15
Ja, stimmt eigentlich... Ich hatte mich halt im Vornherein auf ein Format festgelegt, muss mir mal n neues überlegen...
Ich studier jetzt ma dein ganzes Chatprog und melde mich falls es Probleme gibt.
Fabian W. - Sa 08.10.05 10:24
Hallo,
also gröstenteisl versteh ich den Code bis auf folgende 2 Punkte:
1)
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:
| function TForm1.ConnectToServer(Host: string; NickName: string):string; var str: string; begin result := ''; try Client.Host := Host; Client.Connect; IOHandlerStack.WriteLn(Join+NickName); Timer1.Enabled:=true; except on E: EidSocketError do begin case E.LastError of 10061: str:='Auf der Angegebenen Ip läuft unter dem angegebenen Port kein Server!'; 10060: str:='Die angegebene IP exisitiert nicht.'; else str:='Konnte nicht verbinden.' end; result := str; end; end; end; |
Wird bei mir rot unterstrichen, was muss ich noch tun? Uses-Eintrag??
2)
IOHandlerStack.WriteLn(Join+NickName);Mag zwar sein dass es funzt (weis ich noch net) aber warum funzt das. Ich hab ja nur den Handler auf's Formular gezogen... Benutzt der jetzt den Client oder wie???
jakobwenzel - Sa 08.10.05 10:42
Also, du musst die Unit idStack einbinden, damit er de Fehler korrekt abfangen kann.
im idTCPServer musst du unter IOHandler den idServerIOHandlerStack ein stellen, im Client musst du unter IOHandler den idIOHandlerStack einstellen. Dann sollte es klappen.
Fabian W. - Sa 08.10.05 11:30
Ah! Danke klappt :-)
OK, ich glaube alles richtig umgesetzt zu haben. Ich hab aber leider keine Möglichkeit das zu testen... Könnte ich dir das Projekt bei Gelegenheit schicken, dass du dir das mal anschaust? Nur wenn dir's recht is natürlich.
jakobwenzel - Sa 08.10.05 11:35
Du kannst das Programm doppelt starten, einmal als Client und einmal als Server und als IP 127.0.0.1 (localhost) eingeben. Dann kannst du sehehn, ob es funktioniert.
Fabian W. - Sa 08.10.05 11:36
Super! danke. :-)
Fabian W. - Sa 08.10.05 11:49
| Zitat: |
| Connection Closed Gracefully |
Sagt der Client, wenn ich verbinden will. Egal mit welcher IP... Ich schicke mal den Code zum verbinden...
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:
| function TForm1.ConnectToServer(Host: string; NickName: string):string; var str: string; begin result := ''; try Client.Host := Host; Client.Connect; IOHandlerStack.WriteLn(Join+NickName); Timer1.Enabled:=true; except on E: EidSocketError do begin case E.LastError of 10061: str:='Auf der Angegebenen Ip läuft unter dem angegebenen Port kein Server!'; 10060: str:='Die angegebene IP exisitiert nicht.'; else str:='Konnte nicht verbinden.' end; result := str; end; end; end; |
Was kann da schief gehen??
EDIT: Halt!! Ich hab den Port auf 1025 gesetzt da alle unter 1025 doch für Windows sind oder?? Vorher wars 0. Jetzt kommt die Meldung dass unter der Angegeben IP unter dem angegebenen Port kein Server läuft... Woher weis ich welchen port ich einstellen muss???
Fabian W. - Sa 08.10.05 13:37
Fabian W. hat folgendes geschrieben: |
| EDIT: Halt!! Ich hab den Port auf 1025 gesetzt da alle unter 1025 doch für Windows sind oder?? Vorher wars 0. Jetzt kommt die Meldung dass unter der Angegeben IP unter dem angegebenen Port kein Server läuft... Woher weis ich welchen port ich einstellen muss??? |
A propos: Wie bekomm ich die ID meines Servers raus? Kann ich die im Prog auslesen??
Wie gesagt, hab 0 Ahnung von der Materie, bitte habt Gedult... :oops:
jakobwenzel - Sa 08.10.05 13:39
Hast du den Port bei Server und Client auf 1025 gesetzt?
Fabian W. - Sa 08.10.05 13:45
Ich find beim Server keine Port-eingenschaft?! Kann ich die nur zur Laufzeit einstllen??
jakobwenzel - Sa 08.10.05 13:49
Beim Server heißt die DefaultPort, glaube ich. Aber die sollte im Objektinspektor zu finden sein.
Fabian W. - Sa 08.10.05 13:55
Tja, ich glaub ich sollte zu Augenarzt...
Ok, danke ich hab die ganze Zeit stur nach 'Port' gesucht, da viel mir die andere Eigenschaft net auf. Jetzt funzt's!
Und wie bekomm ich die IP jetzt raus??
jakobwenzel - Sa 08.10.05 14:32
Welche IP? Die des Servers, des Clients...
Fabian W. - Sa 08.10.05 15:42
Ich benötige ja ne IP um als Client den Server zu kontaktieren. Kann ich die aus dem Server auslesen?
Die IP vom Client brauch ich ja net unbedingt zu wissen, muss ich ja nirgends angeben, aber wenn's geht interessiert mich die auch.
Fabian W. - So 09.10.05 09:19
Ok, hab folgendes gefunden:
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:
| Uses WinSock;
function GetIpAddress: string; var phoste: PHostEnt; Buffer: array [0..100] of char; WSAData: TWSADATA; begin result:=''; if WSAStartup($0101, WSAData) <> 0 then exit; GetHostName(Buffer,Sizeof(Buffer)); phoste:=GetHostByName(buffer); if phoste = nil then result:='127.0.0.1' else result:=StrPas(inet_ntoa(PInAddr(phoste^.h_addr_list^)^)); WSACleanup; end;
function IsOnline: Boolean; Var dlvFlag : DWord; begin Result:=False; dlvFlag := Internet_Connection_Modem + Internet_Connection_Lan + Internet_Connection_Proxy; If InternetGetConnectedState ( @dlvFlag, 0 ) = True Then Result:=dlvFlag = 81; End;
Aufruf: If isonline then memo1.lines.add('Internet-IP: '+GetRASIP(1)+'Netzwerk-IP: '+GetIPAddress) else memo1.lines.add('Netzwerk-IP: '+GetIPAddress); |
Diese Funktion gibt mir als meine IP x9x.1x8.17x.2x zurück.
http://checkip.dyndns.org/ sagt aber x0.1x4.12x.2x5.
So, ich hänge hinter nem Router, beziehe meine IP vom Server des Routers... Welche IP ist jetzt die, die ich dann in meinem Prog eingeben muss?? Die von
http://checkip.dyndns.org/ wird wohl die richtige sein, oder?? Aber wie bekommt die mein Prog raus?
EDit: die x'se hab ich mal aus Spass an der Freude da rein gemacht ;-)
Die IP's sind aber verschieden
hallo - So 09.10.05 10:14
Also wenn einer zu dir verbinden will, dann wird schwer: Du musst Portforwarding bei deinem Router einstellen!
Also Anfragen an den Port X werden an 192.168.178.21 Port X weitergeleitet!
Wenn du der Server bist!
Wenn der Andere dann der Client ist, muss er die IP von deinem Router eingeben, der ihn dann zu dir verbindet.
Nach draußen kommst du mit einem Router auch. Da muss man höchstens die Firewall anders einstellen!
Fabian W. - So 09.10.05 10:18
hallo hat folgendes geschrieben: |
Also wenn einer zu dir verbinden will, dann wird schwer: Du musst Portforwarding bei deinem Router einstellen!
Also Anfragen an den Port X werden an 192.168.178.21 Port X weitergeleitet!
Wenn du der Server bist!
Wenn der Andere dann der Client ist, muss er die IP von deinem Router eingeben, der ihn dann zu dir verbindet.
Nach draußen kommst du mit einem Router auch. Da muss man höchstens die Firewall anders einstellen! |
Nach drausen muss ich ja nur die IP vom Server eingeben... Aber wie kommt win Client zu mir? Also gibt mir die Delphi Function GetIpAddress die Adresse zurück, die der Client bei sich eingibt??
hallo - So 09.10.05 10:21
Also der Client muss die IP vom Router eingeben, mit der du im Internet bist!
Dieser macht dann Portforwarding und leitet den Client zu deinem PC weiter!
Fabian W. - So 09.10.05 10:31
Nu weis ich aber net welche die richtige is, und ausprobiern kann ichs auch net...
hallo - So 09.10.05 10:37
Sie bei checkip dyndns etc. ist deine Internet IP!
Mit der 192.168.****** bist du normalerweiße im Netzwerk!
Fabian W. - So 09.10.05 12:13
ok, soll heißen: checkip dyndns liefert die IP die ich (bzw der Client) braucht. Dann erkundige ich mich mal, wie ich Webseiten aufrufe und strings rauskpoiere... Oder gibbet noch andere Möglichkeiten?
hallo - So 09.10.05 13:53
Nimm am besten urldownloadtofile mit der unit urlmon damit geht am einfachsten!
Hab ich auch schonmal sowas gemacht!
Und dann musst du nur noch aus dem string 'Current IP Address: XX.XXX.XX.XXX' die IP rauslesen! Das dürfte einfach gehen!
Was auch noch praktisch wäre: sowas wie deinservername.homeip.net
Dann passt sich die IP automatisch an!
Ein Freund von mir hat sowas und das funktionert!
Fabian W. - So 09.10.05 15:34
hallo hat folgendes geschrieben: |
Was auch noch praktisch wäre: sowas wie deinservername.homeip.net
Dann passt sich die IP automatisch an!
Ein Freund von mir hat sowas und das funktionert! |
Ich wieß jetzt net genau was du meinst, aber das Mit UrlDownloadToFile is ne gute Idee.
Fabian W. - So 09.10.05 15:57
Wie sollte es anders sein: UrlDown... läd nix runter weil ich ja keine bestimmte datei angebe, ich weiß nur die URL, die kann er aber schlecht runterladen. Jemand ne Idee wie ich das deixeln könnte??
Tobias1 - So 09.10.05 16:18
Nimm ein Indy HTTP Client und kopier die IP grad aus dem String raus:
Delphi-Quelltext
1:
| idhttp1.Get('http://checkip.dyndns.org/'); |
Tobias1 - So 09.10.05 16:30
Ich hab ein bisschen dran rumgebastelt
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| function tform1.getmyipaddress: string; var a:string; httpindy:Tidhttp; begin httpindy:=Tidhttp.Create; a:=httpindy.Get('http://checkip.dyndns.org/'); result:=copy(a, pos('Address:',a)+9 ,pos('</body></html>',a)-pos('Address:',a)-9); httpindy.Free; end; |
alias5000 - So 09.10.05 16:44
geht das nich mit der Komponente TidIPWatch?
Fabian W. - Mi 12.10.05 15:22
checkip.dyndns.org/
Gibt mir anscheinend ne Ip zurück die mir als Client nix bringt.
@
jakobwenzel: Wie hast du das gemacht??
jakobwenzel - Mi 12.10.05 15:47
Du meinst die Ips? Im lokalen Netz hab ich im Router geschaut, für Internet hab ich Port-Forwarding aktiviert, und meine IP auch im Router (meiner zeigt das an)nachgeschaut und dem Client über ein Forum mitgeteilt.
Eine Möglichkeit wäre es, auf einem Webspace ein PHP-Skript zu haben, welches die angeschlossenen Server verwaltet, im Delphi-Programm kann man dann einen Server auswählen.
Fabian W. - Mi 12.10.05 16:06
jakobwenzel hat folgendes geschrieben: |
Du meinst die Ips? Im lokalen Netz hab ich im Router geschaut, für Internet hab ich Port-Forwarding aktiviert, und meine IP auch im Router (meiner zeigt das an)nachgeschaut und dem Client über ein Forum mitgeteilt.
Eine Möglichkeit wäre es, auf einem Webspace ein PHP-Skript zu haben, welches die angeschlossenen Server verwaltet, im Delphi-Programm kann man dann einen Server auswählen. |
Ne, ich hab auf nem FTPServer ne Ini liegen, die die dinger 'verwaltet'. Meine FritzBox zeigt meine Iop zwar auch an, nur is das die selbe wie die von checkip.dyndns.org/ und die funzt net. PortForwarding hab ich bei meiner FritzBox net gefunden... Außerdem soll das Propgramm ja auch von Leuts ohne Router oder sonstiges benutzt werden können, dh: Mein Prog soll die Ip rausfinden aber WIE???
Fabian W. - Sa 22.10.05 09:08
So, hab nochmal ne Frage:
Die Ip meines PC im Inet hab ich ja jetzt. Wie bekomm ich die lokale Ip (netzwerk) raus, die ich für'n Netzwerkchat brauch?
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:
| function getIPs: Tstrings; type TaPInAddr = array[0..10] of PInAddr; PaPInAddr = ^TaPInAddr; var phe: PHostEnt; pptr: PaPInAddr; Buffer: array[0..63] of Char; I: Integer; GInitData: TWSAData; begin WSAStartup($101, GInitData); Result := TstringList.Create; Result.Clear; GetHostName(Buffer, SizeOf(Buffer)); phe := GetHostByName(buffer); if phe = nil then Exit; pPtr := PaPInAddr(phe^.h_addr_list); I := 0; while pPtr^[I] <> nil do begin Result.Add(inet_ntoa(pptr^[I]^)); Inc(I); end; WSACleanup; end; |
Diesen Code hab ich aus diesem
http://www.delphi-library.de/viewtopic.php?sid=b60536b0156605cbe97e4a81592f86e4&t=120&start=0&postdays=0&postorder=asc&highlight=
Topic. Kann ich den verwenden?
Ich kann das, in Ermangelung eines Netzwerks, nicht testen, bitte um Verständnis.
mfg
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 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!