C# P2P Verbindung herstellen

Kokujou

Lieutenant
Registriert
Dez. 2017
Beiträge
929
Hallo ihr Lieben,

Ich bin mal wieder völlig am Ende mit meinem Latein.
Ich versuche krampfhaft irgendwie ein Netzwerk-Spiel auf die Beine zu kriegen. Mit Unity hats funktioniert, aber diese grundbösen Menschen haben beschlossen, einfach mal die Verbindung nach ein paar Sekunden zu trennen. Keep Alive bringt erstmal gar nichts.

Also bin ich jetzt bei TcpClient/Listener aus System.Net.Sockets.
Aber hier krieg ich gar nicht erst eine Verbindung aufgebaut. Lokal geht, aber danach krieg ich eine SocketException.
Und nein: Ich suche keine Problemlösung bei der man irgendwelche Neustarts, Treiberinstallationen oder Firewalleinstellungen vornehmen muss.

Schließlich soll jeder der Spieler das machen können. Die IPv6 Adresse, die ich zum Verbinden benutze beziehe ich aus nem Webrequest. Das war wohl mit diee inzige Möglichkeit die keine 100 Zeilen erfordert.

Ich hab es sowohl auf Android als auch auf PC getestet und kriege jedes mal die Meldung, dass es aktiv die Verbindung verweigert. Kennt ihr irgendwelche besseren Anbindungen? Es kann doch nicht so schwer sein Daten von A nach B zu senden. Ich arbeite schon so low-level dass ich die Daten selbst serialisiere und mit Nachrichten arbeite statt mit irgendwelchen Synchronisierten Variablen oder Funktionen die entweder auf Client oder Server ausgeführt werden.
 
Kokujou schrieb:
Also bin ich jetzt bei TcpClient/Listener aus System.Net.Sockets.
Aber hier krieg ich gar nicht erst eine Verbindung aufgebaut. Lokal geht, aber danach krieg ich eine SocketException.
Und nein: Ich suche keine Problemlösung bei der man irgendwelche Neustarts, Treiberinstallationen oder Firewalleinstellungen vornehmen muss.
Wie stellst du dir das vor? Bei jeder Netzwerkverbindung muss man die Firewall beachten, weil es nun mal der Job der Firewall ist, Netzwerkverbindungen zuzulassen oder zu blockieren. Wenn sich der Nutzer nicht selbst um die Firewall kümmern soll, fügt man die notwendigen Ausnahmen bzw. Regeln im Setup hinzu. So wie es beispielsweise passiert, wenn man einen VNC-Server installiert und der dann Port 5900 in der Firewall einträgt. Du kannst aber nicht einfach die Augen zukneifen und hoffen, dass die Firewall plötzlich verschwindet.

Du schließt aber kategorisch gängige Lösungswege von vornherein aus, daher weiß ich nicht so recht was du nun erwartest.
 
und wie macht man das bei Android?

Es gibt doch tausende Anwendungen die mit dem TCP Zeug arbeiten. ... Es sieht so aus als müsste ich jetzt nen Server einbauen und über den kommunizieren :'(
 
Es gibt da bspw. Hole Punching. Aber ansich muss entweder der Weg frei sein (sprich NAT + Firewall passend eingestellt oder eben Hole Punching) oder aber der Umweg über ein Server gegangen werden.
 
Bringt es was einen Port zu nehmen der vermutlich frei ist oder wird der dann durch die Anwendung "blockiert"?
Port 80 z.B. ist ja für HTTP oder?
 
Wie kommst du darauf, dass der vermutlich frei ist? Bei praktisch keinem Endnutzer sollte der "frei" sein. Und bei Android müsstest du (unter "normalem" Linux ist das so) Root brauchen, um auf Ports unter 1024 lauschen zu können.
 
das ist doch... einfach toll. Unity versagt, weil dort sich die clienten nach ner weile einfach mal so abmelden und P2P geht nicht weil das den nutzer vor unlösbare probleme stellt.
Erstklassig...

Langsam hasse ich es dass ich programmierer wurde. Simpelste Dinge werden zu wahren Herkules-Aufgaben. Und Support ist seitens Unity weder in irgendeinem Forum zu kriegen noch sonst irgendwo...

Denn Unity stellt ja eigentlich einen Server zur Verfügung, der die Kommunikation handhabt. Weiß der Geier wer auf die Idee kommt, dass sich die Klienten nach ner ZEit einfach abmelden.
 
Eine Frage bevor ichs mir anlese: Gibts auch nur die Geringste Chance dass das in Android funtkioniert?
Ist das eigentlich im System Namespace drinne? Falls nicht könnte das wahrscheinlich ziemlich unmöglich werden...
 
Ich versteh Deine Frage nicht so ganz ehrlich gesagt. Wie wär's mal mit ner konkreten, ausführlichen Fehlermeldung und Stacktrace etc.? Was heißt aktiv Verbindung verweigern?

Softwareentwicklung heißt oft sich mit vermeintlich einfachen aber sich dann doch als komplex herausstellendenken Themen auseinanderzusetzen. Und Netzwerkkommunikation ist komplex ...
 
Eigentlich ist Netzwerkkommunikation ganz und gar nicht Komplex. Herrgott ich will nur ein byte Array von A nach B senden, nichts anderes tue ich hier doch auch.

Die Fehlermeldung die ich beim TcpClient kriege ist SocketException: Zielcomputer verweigert die verbindung.

Das ist wohl das was ihr schon gesagt hab ich müsste irgendeine Port-Schande machen aber ich kann nicht von jedem der Nutzer verlangen erstmal in ihrem Router rumzufingern. Und Unity, die Engine mit der ich die Anwendung entwickle, hat kein UPNP soweit ich weiß.
 
Dann sieh Dir mal SSDP Library for UPnP version 2.0 an.
Da steht:
This library is created for .NET Standard 2.0 making it modern and ready for the future. Also, the library seeks to balance broad compatibility with simplicity by supporting only the most recent platforms - i.e. iOS, Android, UWP (16299+), .NET Core 1.0+ and .NET 4.6.1+ and Mono.
Also sollte es mit für Deinen Zweck ausreichend sein.
 
Jungs wovon redet ihr ? Wir reden hier gerade von 2 Android Smartphones die im selben (W)LAN sind?! Da ist doch in aller Regel bei den meisten Routern keine Firewall zwischen im LAN Segment. Oder verstehe ich das falsch @Kokujou

edit: hab mir den Thread noch mal ein zweites Mal durchgelesen. @Kokujou kannst du mal ein paar mehr Details geben? Ist das ein Internet Spiel oder LAN? Was heißt die IPv6 Adresse holst du dir über einen Webrequest? Klingt doch nach einem Spiel welches über das Internet funktionieren soll.
 
Zuletzt bearbeitet:
Kokujou schrieb:
Eigentlich ist Netzwerkkommunikation ganz und gar nicht Komplex.
Ähm.. doch?

Bei einer Netzwerkverbindung sind etliche Komponenten beteiligt, bei Verbindungen über verschiedene Netzwerke hinweg diverse Router und auch noch potentiell mehrere Firewalls und über das Internet zudem noch NAT. Darüber hinaus hat ein PC und auch ein Smartphone noch eine eigene Firewall im Betriebssystem. Ohne dir jetzt auf den Schlips treten zu wollen: Kennst du dich denn mit Firewall, Routing, NAT, TCP/UDP aus? Oder ist das deine erste Netzwerkanwendung, die du programmierst? Wie gesagt, nicht bös gemeint, sondern nur eine Frage zum besseren Verständnis.

Auf welchem Port hört deine Anwendung denn zur Zeit?
Ist das evtl. ein Systemport (<1024) und das OS blockiert bereits das Öffnen des Ports?
Wie genau testest du bzw. wie sieht das Test-Setup aus? (zB Ziel hinter einem NAT-Router)
Hast du dir mal mit WireShark angeschaut was auf der Leitung passiert bzw. ob überhaupt am Zielsystem Pakete ankommen?

Im Idealfall hast du auf beiden Seiten zunächst ein PC-System mit einem OS deiner Wahl und nicht direkt ein Smartphone. Das erleichtert nämlich das Debugging ungemein.
 
Es ist ein Internet Spiel. Es soll außerhalb des lokalen Netzwerks funktionieren, aber ich hab es innerhalb getestet und nichtmal da funktioniert es. Zumindest nicht mit Tcp. Die Gründe wurden ja schon dargelegt.

Ein Wort zu externen Bibliotheken: Unity unterstützte die Basis des .Net Frameworks also System.xxx
Soweit ich weiß sind sie immerhin bei .Net 4.5 gelandet. Allerdings bin ich nicht sicher wie das mit externen Bibliotheken aussieht, besonders im Punkto Crossplattform dürfte es da große Schwierigkeiten geben.

Aber gut andererseits steht da Mono... und ich glaub Mono hat irgendwas mit Unity zutun, das könnte die Lösung sein. Drücken wir mal die daumen!
Ergänzung ()

Und ja ihr habt recht das ist meine erste Netzwerkanwendung und ich bin völlig schockiert, dass sogar das kleinste Denkbare Szenario so wahnsinnig komplizierte Dinge erfordert. Das wird mich noch in meinen Alpträumen verfolgen.

Ich benutze Port 9000, was TCP und UDP ist weiß ich aber zumindest ;) darum brauch ich auch dringend TCP und würde das nur ungern auf low-level selbst bauen. ist zwar machbar aber ich komm bei sowas gern mal durcheinander^^ Senden... Bestätigen... Bestätigung der bestätigung... und braucht die dann auch ne bestätigung? XD aber egal. das wäre ja nur das kleinste Problem.

Tatsächlich habe ich zwecks Debugging ein PC-System bemüht, einfach weil das Android Debugging tausend mal länger dauert, insbesondere da ich das APK file übers lokale Netzwerk hochladen, runterladen und dann manuell installieren muss >.> aber auch über PC gab es das Problem... interessanterweise sogar wenn ich auf demselben PC 2 Programme laufen lasse und die miteinander über ihre Externe IP kommunizieren lasse.

Das ist doch wohl mal sehr interessant...
 
Joa dann haben alle natürlich recht. Im Internet blockt die Router Firewall alle Direktverbindungen, außer man hat die Ports entsprechend freigegeben. Ein Server im Internet wo der Client (dein Spiel) die Verbindung dann hin aufbaut würde das Problem natürlich lösen, was du nicht möchtest. upnp wie schon erwähnt könnte eine Lösung sein. Ansonsten habe ich hier noch eine Diskussion gefunden:
https://www.reddit.com/r/Unity3D/comments/7tpiyn/creating_a_multiplayer_game_using_unet_do_i_need/

update: im LAN sollte das ganze aber funktionieren. Wenn du nicht mit 2 Smartphones getestet hast vermute ich mal, dass am PC die Windows Firewall aktiv war welches die Verbindung weggeblockt hat. Oder an einen der Geräten ist gar kein ipv6 aktiv? ;)
 
Wie gesagt, denk an die Firewall des Betriebssystems. Selbst Windows ist so schlau, dass es alle Anfragen von unbekannten IPs (=IPs außerhalb des eigenen lokalen Subnetzes) blockiert. Das heißt selbst wenn du eine Prtweiterleitung einrichtest blockt das Betriebssystem selbst die Verbindung ab.
Ergänzung ()

Der mehr oder weniger vollständige Vorgang sieht so aus:


PC_A sendet Daten an WAN_IP_B auf Port 9000
--> A's Firewall prüft ob die ausgehenden Regeln dies erlauben
--> A reicht die Daten an das Standard-Gateway weiter (Router), weil das Ziel nicht im lokalen Netz liegt
--> Router prüft in seiner Firewall am LAN eingehend sowie am WAN ausgehend ob der Traffic zulässig ist
--> Router leitet den Traffic an sein Standard-Gateway weiter (Provider)
------------------------ Routing quer durchs www ----------------------
Traffic kommt am Router mit der WAN_IP_B auf Port 9000 an
--> Router prüft ob der Traffic für ihn selbst ist
--> Router prüft ob er eine Portweiterleitung für Port 9000 hat
--> Router prüft seine Firewall ob der Traffic zulässig ist
--> Router leitet an Ziel-PC auf Port 9000 weiter
--> Ziel-PC prüft seine eingehenden Firewall-Regeln ob Traffic auf Port 9000 von WAN_IP_A zulässig ist
--> Betriebssystem reicht Traffic auf Port 9000 an Anwendung weiter


Ist natürlich etwas vereinfacht formuliert, aber im Prinzip läuft das so - wenn ich nix vergessen oder verdreht habe.

Wenn die Rückmeldung sagt, dass die Verbindung abgelehnt wurde, blockt vermutlich die Firewall des Ziel-Routers (zB wegen fehlerhafter/fehlender Portweiterleitung) oder aber die Firewall des Ziel-PCs blockt selbst. Prüfe daher die Portweiterleitung im Ziel-Router sowie die lokale Firewall des PCs. Dort muss in den eingehenden Regeln Port 9000 explizit auch für Quell-IPs jenseits des lokalen Subnetzes freigegeben sein.
 
Zuletzt bearbeitet:
Tja Unet baut halt einen Server auf, weswegen man hier kein NAT Zeug braucht. Sobald die Verbindung aber endlcih steht ist der Rest nur noch simpel. Das ganze Synchronisieren von Spielerpositionen ist ja nix weiter als das permanente hin und her schicken von Nachrichten.

Also kann ich mir P2P abschminken, es sei denn ich kriege UPNP zum Laufen.

Das schönste wäre es natürlich, wenn ich einfach einen Server finden würde der mich nicht nach 2 Minuten rausschmeißt. Dann könnte ich das so beibehalten. Oder ich baue tatsächlich selbst einen Server.

Nur zum Verständnis: Wie funktioniert das eigentlich? Ich meine bei P2P ist ja klar, man löst ein event aus wenn die nachricht empfangen wird, ganz typisch und verständlich.

Aber Web-Server funktionieren ja eben nicht so. Hier wird es über Requests geregelt. ich rufe also den Server auf und sage ihm "Gib mir die Nachricht xxx" oder so. Heißt das der Client ruft in Dauerschleife solange vom server Informationen ab, bis der antwortet? Also in etwa:

Client1 sendet Nachricht A an Server
Server setzt Nachricht für Client 2 auf Nachricht A
Client 2 ruft neue Nachricht ab bis Rückgabe nicht leer
Client 2 bekommt Nachricht A vom Server
Client 2 bestätigt Empfang der Nachricht
Server löscht Nachricht A für Player 2 sodass nächste Rückgabe leer ist

???
 
Irgendwie habe ich jetzt den Faden verloren. Ich dachte du programmierst Client und Server?!? "Unet" sagt mir nix.

Eine Netzwerkverbindung ist bidirektional. Beide Seiten können aktiv Nachrichten schicken. Ein Client kann also prinzipiell sowohl einen Request an den Server schicken als auch Requests vom Server erhalten. Ist alles nur eine Frage wie das Kommunikationsprotokoll der Anwendung aufgebaut ist. TCP bzw. UDP stellen ja nur die Transportschicht (Layer4) dar. Im Falle von TCP vergleichbar mit einem Einschreiben mit Rückschein bei der Post. Wie man den Inhalt des Einschreibens aka TCP-Pakets zu interpretieren hat, ist Aufgabe des Empfängers alias die Anwendung.
 
Kokujou schrieb:
Das schönste wäre es natürlich, wenn ich einfach einen Server finden würde der mich nicht nach 2 Minuten rausschmeißt.
TCP/IP funktioniert so, dass zunächst eine Verbindung aufgebaut wird (TCP Handshake), dann Daten ausgetauscht werden und dann die Verbindung wieder beendet wird. Wenn der Server also die Verbindung beendet, musst du mal prüfen warum. Z.B. durch ein Time-Out, weil der Client seit X-Sekunden keine Daten mehr gesendet hat etc.

Sonst wäre es nicht schlecht, sich mal in die Grundlagen einzuarbeiten, wenn man was mit Netzwerken programmieren will:
http://www.codeplanet.eu/tutorials/csharp/4-tcp-ip-socket-programmierung-in-csharp.html
 
Zurück
Oben