P2P Netzwerk (mit UDP) trotz NAT (Firewall auf Router)

  • Hallo, ich habe ein kleines Problem:

    Ich würde gerne ein Multiplayerspiel programmieren, das aber nicht über einen festen Server läuft (weder die Möglichkeit solch einen zu haben, noch wäre das bei vielen Spielern sinnlos, da sehr hoher traffic etc). Deshalb soll das Spiel über peer to peer laufen. Im privaten Netzwerk (bzw. Hamachi) funktioniert das einwandfrei, aber ich würde es auch gerne schaffen, dass man nicht hamachi haben muss. (nein, port forwarding kommt auch nicht in Frage, da das nicht jeder einstellen kann, es ist für eine breite Masse gedacht.)Dazu habe ich mich mal bei google informiert und diese Methode gefunden (wird z.b. von skype benutzt): http://en.wikipedia.org/wiki/UDP_hole_punching

    Also gleich mal ausprobiert, aber in dieser Form klappt es leider mit einem Freund nicht. (Beide hatten das gleiche Programm gleichzeitig laufen, natürlich aber die IPs richtig angepasst.)

    [autoit]


    Global $other_ip = "andere IP hier eintragen."
    Global $eigene_ip = @IPAddress1
    Global $port = 5478

    [/autoit][autoit][/autoit][autoit]

    Global $udp_bind
    Global $udp_open

    [/autoit][autoit][/autoit][autoit]

    AdlibRegister("standard_send", 500)

    [/autoit][autoit][/autoit][autoit]

    UDPStartup()

    [/autoit][autoit][/autoit][autoit]

    $udp_bind = UDPBind($eigene_ip, $port)
    if @error Then MsgBox(0, "bind", @error)

    [/autoit][autoit][/autoit][autoit]

    $udp_open = UDPOpen($other_ip, $port)
    if @error Then MsgBox(0, "open", @error)

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    While 1
    $recv = UDPRecv($udp_bind, 2048)
    If $recv <> "" Then
    MsgBox(0, "Nachricht:", $recv)
    EndIf
    ToolTip("warte auf msg...", 0, 0)
    WEnd

    [/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit]

    Func standard_send()
    UDPSend($udp_open, "Standard_send")
    if @error Then MsgBox(0, "send", @error)
    TrayTip("Nachricht gesendet", "Nachricht an "&$other_ip&" gesendet!", 0)
    EndFunc

    [/autoit]

    Eventuell kann das noch jemand selbst testen, ob das bei ihm auch nicht funktioniert, oder ob das einfach an unseren Routern lag. Es wäre nett, wenn da jemand Bescheid weiß und mich aufklären könnte bzw sogar zeigen könnte, wie es sein müsste.

    Danke schonmal im Voraus :)

  • naja aber man brauch ein richtigen server wenn man das mit php macht is der die ganzezeit nur am laden und zieht leistung, denn soweit ich weis kann php nur aktionen durchführen wenn eine "php-aktion" gestartet wird bzw. aufgerufen wird. besser währ es per tcp eine nachricht vom richtigen server empfangen zu lassen statt die ganze zeit ne webseite aufzurufen um zu checken ob es eine "nachricht" gibt.
    wenn ich mich irre und eine andere möglichkeit gibt via normalen host server durch z.B php würd ich es gerne wissen^^

    Sind TV-Quizfragen zu einfach? A) Ja B) Harry Potter

    Spoiler anzeigen

    Ich gebe zu dieser Post hat wahrscheinlich nicht viel geholfen,
    aber ich versuche wenigstens zu helfen :rolleyes:

  • ProGamer Es gibt eine Möglichkeit über PHP, und zwar gab/gibt es eine Seite, die die IP Adressen aller Clients anzeigt die in den letzten x Minuten die Seite aufgerufen haben, wobei jeder dieser Listen eine ID zugewiesen wurde, sodass in einer Liste auch nur die Clients stehen, die das jeweilige Programm benutzen. Das wurde hier im Forum irgendwann mal erwähnt, ich habe den Post aber noch nicht gefunden.

    @matinto Das Problem könnte sein, dass die beiden Clients sich relativ zeitgleich miteinander verbinden müssen. Du könntest also so lange UDPOpen benutzen, bis auf dem UDPSocket Daten von dem anderen Client empfangen werden, denn dann war der Verbindungsaufbau erfolgreich.

  • Also der eine Server in der Mitte ist vorhanden, dafür würde ich einen kostenloses hoster mit php und mysql benutzen. Wenn die IPs aber schon bekannt sind, wird der (jedenfalls im Test) noch nicht benötigt.

    BinDannMalWeg: Der Link ist mir schon bekannt, er hat mir auch wirklich geholfen das zu verstehen, trotzdem danke :)

    @James1337: Sendet er denn mit UDPOpen auch schon eine Nachricht? (oder muss man die nachricht explizit mit UDPSend senden?

    Und hier im Forum hab ich auch schon geguckt, aber wirklich nichts in der art gefunden...

  • @James1337: Sendet er denn mit UDPOpen auch schon eine Nachricht? (oder muss man die nachricht explizit mit UDPSend senden?

    Der Client (C1), der zu dem anderen Client (C2) verbinden will (wobei in diesem Fall C2 der Server ist), muss, nachdem die Verbindung steht ein "OK" oder igendwas senden, damit C2 mit dem Versuch aufhören kann, zu C1 zu verbinden. Und dann das Ganze nochmal umgekehrt.

    MfG, James

  • ne ich meinte ob die Funktion UDPOpen auch schon versucht sich zu verbinden (also ein "verbindungspacket" sendet). Ich ging nämlich davon aus, dass die Funktion nur ein Objekt erzeugt, damit die Funktion UDPSend dann weiß wohin es sich verbinden muss. Also konkret: Sendet UDPOpen auch schon was an den anderen?

  • okay, ich habs gerad mal probiert wirklich häufig UDPOpen zu verwenden, aber es funktioniert immer noch nicht...

    hier das diesmal verwendete skript:


    [autoit]


    Global $other_ip = "andere ip"
    Global $eigene_ip = @IPAddress1
    Global $port = 5478

    [/autoit][autoit][/autoit][autoit]

    Global $udp_bind
    Global $udp_open

    [/autoit][autoit][/autoit][autoit]

    AdlibRegister("standard_send", 15000)
    AdlibRegister("open", 12)

    [/autoit][autoit][/autoit][autoit]

    UDPStartup()

    [/autoit][autoit][/autoit][autoit]

    $udp_bind = UDPBind($eigene_ip, $port)
    if @error Then MsgBox(0, "bind", @error)

    [/autoit][autoit][/autoit][autoit]

    $udp_open = UDPOpen($other_ip, $port)
    if @error Then MsgBox(0, "open", @error)

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    While 1
    $recv = UDPRecv($udp_bind, 2048)
    If $recv <> "" Then
    MsgBox(0, "Nachricht:", $recv)
    EndIf
    ToolTip("warte auf msg...", 0, 0)
    WEnd

    [/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit]

    Func standard_send()
    UDPSend($udp_open, "Standard_send")
    if @error Then MsgBox(0, "send", @error)
    ;TrayTip("Nachricht gesendet", "Nachricht an "&$other_ip&" gesendet!", 0)
    UDPCloseSocket($udp_open)
    if @error Then MsgBox(0, "close", @error)
    $udp_open = UDPOpen($other_ip, $port)
    if @error Then MsgBox(0, "open_during", @error)
    EndFunc

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    Func open()
    $udp_open = UDPOpen($other_ip, $port)
    ToolTip("open", 0, 0)
    EndFunc

    [/autoit]
  • Euch ist aber schon klar, dass ihr dem anderen Client mit eurer IP auch den ausgehenden Port weiterreichen müsst? Und genau da liegt das Problem: Mit Autoit ist es, so viel ich weis, nicht möglich diesen Port zu ermitteln... :P

    LG
    Christoph :)

  • Euch ist aber schon klar, dass ihr dem anderen Client mit eurer IP auch den ausgehenden Port weiterreichen müsst? Und genau da liegt das Problem: Mit Autoit ist es, so viel ich weis, nicht möglich diesen Port zu ermitteln... :P


    Wobei wir wieder bei dem Thema wären, wie verdammt schlecht die Netzwerkfunktionen in AutoIt umgesetzt sind... Aber du hast natürlich Recht. Und ja, es war mir klar, nur daran gedacht habe ich nicht... ^^ Durch einen DllCall sollte sich dieses Problem aber auch lösen lassen... irgendwie.

  • Wisst ihr zufällig ob man mit php den ausgehend port herausfinden kann z.b., oder wie man das sinnvoll macht?

  • Zitat

    Wisst ihr zufällig ob man mit php den ausgehend port herausfinden kann z.b., oder wie man das sinnvoll macht?


    Was glaubst du denn, warum noch nicht ein einziger Autoit-Kundiger UDP-Hole-Punching umgesetzt hat? ^^
    Naja vielleicht hast du Glück und irgend Jemand hat einen Gedanken-Blitz... Möglicher Weise lässt sich mit Hilfe einer DLL wirklich abfragen, über welchen Port eine Anwendung kommuniziert.

    LG
    Christoph :)