socketverbindung p2p übers Internet hinter einem Router

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Benutzeravatar
Spaten
User
Beiträge: 52
Registriert: Samstag 27. Mai 2006, 11:35
Wohnort: Bremen
Kontaktdaten:

Hallo zusammen,

ich habe mich vor einiger Zeit etwas über Sockets schlaugemacht und habe auch
schon einfache Sachen übers LAN ausprobiert. Allerdings scheitern meine Versuche,
eine Verbindung mit einem Client außerhalb des LANs herzustellen,
was meiner Meinung nach auch kein Wunder ist,
da man hier ja im seltensten Fall "direkt" an den Client herankommt.
Hier mal ein Bild:
Bild

Mal angenommen, ich wäre Client1 und erfrage beim Server
(dessen Adresse in meinem Programm fest eingegeben ist)
die IP-Adresse von Client3, um eine direkte Verbindung mit ihm aufzubauen.
Der Server würde mir doch dann die IP-Adresse von Router-B zurückgeben.
Mit dieser IP-Adresse kann ich jedoch nur Router-B anschreiben und nicht
Client3.

Die Frage ist nun, wie ich über ein Socket mit Client 2, 3 oder 4 kommunizieren kann,
wenn ich doch immer nur die IP-Adresse von den Routern A und B bekomme.

Wenn meinetwegen Client3 so horcht:

Code: Alles auswählen

#socketobjekt erzeugen
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Port 2000 abhören
listener.bind(('', 2000))

# warten, bis jemand eine Verbindung anfordert 
listener.listen(5)

# Verbindung bestätigen
conn, addr = listener.accept()
und Client1 versucht, so eine Verbindung aufzubauen:

Code: Alles auswählen

# Socketobjekt erzeugen
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Versuchen, mit Client3 eine Verbindung aufzunehmen
conn.connect(("84.20.12.149", 2000))
In diesem Beispiel würde die Anfrage von Client1 doch garnicht bei
Client3 ankommen, oder? Woher sollte Router-B wissen, an welchen der beiden Clients die Anfrage soll? (Mal angenommen, alle Ports sind offen)

Hat jemand eine Idee?

Irgendwie muss es ja gehen, bei ICQ werden Dateitransfers
ja auch nicht über den Server umgeleitet, sondern direkt geschickt
(zumindest bis Version 5)
Python-Version: 2.5
Lonestar
User
Beiträge: 147
Registriert: Samstag 9. August 2008, 08:31

Hi, ich hatte mich vor einiger Zeit auch mal n bisschen schlau gemacht was das Thema angeht - allerdings ist das meiste bei mir auch schon wieder verflogen - fürchte ich.
Wie das ganze bei ICQ läuft kann ich leider nicht sagen, da kenne ich mich nicht wirklich mit aus.
Die einfachste Variante wäre, glaube ich, einfach auf dem Router vor Client 3 einen Port an den Client3 weiterzuleiten. Wenn Client 3 dem Server auch noch seinen Port meldet, der für ihn im Router freigeschaltet ist kann ich mit Client 1 auf die IP von Client 3 (eigentlich ja der Router) mit dem passenden Port zugreifen - der Port wird ja vom Router direkt an Client 3 weitergereicht.

UDP wäre soweit ich weiss auch noch eine lösung. Zimindest meine ich das skype das ausnutzt um auch Firewalls zu umgehen.

http://www.heise.de/security/Wie-Skype- ... ikel/82054

ich hoffe mal ich hab hier jetzt keinen Blödsinn verzapft - bei Fehlern bitte melden...

Gruß
Sebastian
kaschu
User
Beiträge: 25
Registriert: Sonntag 25. Februar 2007, 14:15

Hallo Spaten,

Drei Lösungsansätze bieten sich an:

1) Auf Router B werden Portweiterleitungen eingerichtet: Port 2000 nach Client 3 leiten, Port 2001 nach Client 4 weiterleiten. Die Auswahl der Clients erfolgt dann über die Sockets: 84.20.12.149:2000 ist Client3, 84.20.12.149:2001 Client4 usw.
Der Nachteil liegt auf der Hand: unflexibel und aufwändig für den Routeradmin auf der Client-Seite ;)

2) UPnP: wenn die Router auf der Clientseite upnp können, dann könnte die Clientsoftware die Portweiterleitung selbst konfigurieren. Ich habe allerdings noch keine UPnP-Implementierung in python unter meinen Fingern gehabt.

3) Etwas selbst programmieren: alle Clients melden sich am Server an. Diese "Anmeldung" dient zwei Zwecken: 1. Server kennt die IP-Adressen der Clients und 2. die beteiligten Router leiten die Verbindungen weiter, das diese von den eigenen Clients aufgebaut worden sind. Diese "Anmeldung" kann per UDP relalisiert werden. Vorteil: auf dem Server sind nicht zig TCP-Connections aktiv.

Wenn nun Client 1 mit Client 3 Kontakt aufnehmen will, fragt er nicht den Server nach der Adresse, sondern sendet seine Daten für Client 3 an den Server. Dieser leitet die Daten dann an Client 3 über die bestehende Verbindung weiter. Die Antwort von Client 3 geht ebenfalls über den Server, der diese an den Client 1 weiterleitet.

Das Protokoll könnte man noch dahingehend aufbohren, dass der Server beiden Clients einer Kommunikation jeweils die Adressen und Ports des anderen Clients nennt und diese Versuchen, per UDP direkt miteinander Kontakt aufzunehmen. Durch diesen parallelen Kontaktaufbau schalten die meisten SOHO-Router die Leitung frei, weil ja genau von der Adresse/Port etwas hereinkommt, zu dem der eigene Client vorher etwas gesendet hat.

Du siehst, es wartet viel Arbeit auf Dich :shock:


Gruß
kaschu
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Zwei Links wie sowas geht: NAT traversal und How Skype & Co. get round firewalls.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Spaten
User
Beiträge: 52
Registriert: Samstag 27. Mai 2006, 11:35
Wohnort: Bremen
Kontaktdaten:

ok, danke erstmal für die Antworten,
das muss ich mir erstmal genauer ansehen :lol:
Python-Version: 2.5
Antworten