TcpClient/Listener, P2P-Netz und Fehler 10048

Sunray

Erfahrenes Mitglied
Hi,

ich versuche gerade eine art P2P-Netzwerk zu programmieren. Naja eigentlich ein Hybrid-Netz:

Alle clients loggen sich auf einem Server ein, schicken eine eindeutige ID, einen Anzeigenamen und die eigene Adresse (IP + Port) an diesen Index-Server.
Vom Server können alle Clients diese Informationen abfragen.

Ich möchte das ganze mit TcpClients und TcpListenern realisieren, da damit sehr einfach eine Kommunikation in beide Richtungen möglich ist. Damit sollte es doch auch möglich sein auf dem selben PC Server und Clients unter je verschiedene Ports laufen zu haben. Allerding bekomme ich immer den "Normalerweise darf jede Socketadresse (Protokoll, Netzwerkadresse oder Anschluss) nur einmal verwendet werden".
Was mich dabei irritiert ist das "Normalerweise" und "Protokoll, Netzwerkadresse oder Anschluss".

Ich "übersetze" Anschluss jetzt mal mit Port. Diese Fehlermeldung würde also heissen: "Jedes Protokoll, Jede Netzwerkadresse und jeder Port darf nur einmal verwendet werden"
Ist unter Netzwerkadresse ein IP oder eine Hardwareadresse zu verstehen?
Das Tcp-Protokoll kann mehrere Male verwendet werden und es können verschiedene Programme gleichzeitig auf verschiedenen Ports auf dem selben PC laufen.

Ok, ja. Ich habe kaum Ahnung von Netzwerkprogrammierung aber könntet ihr mir bitte sagen, was ich falsch mache?

Danke!
 
Hi.

Das wird ein Problem mit dem TcpListener sein. Du kannst auf jedem PC gleichzeitig nur einen Listener haben der auf einem bestimmten Port lauscht. 2 auf den selben geht nicht, 2 auf 2 verschiedene Ports geht.

Ich schätze mal du willst es so machen, das ein Server/Client/Wasauchimmer auf einem Port lauscht das sich jemand anderes einloggten kann. Und es sollte möglich sein das sich mehrere User einloggen können.

Dazu erstellst dir einfach den TcpListener, startest das 'lauschen'.
Dann sollte dein Programm, oder ein Thread davon, in eine Schleife fallen.
Mit der AcceptTcpClient erstellst du einen neuen TcpClient. Da die Methode aber solange blockiert bis eine Anfrage kommt wird natürlich immer erst ein TcpClient erstellt, wenn auch eine Anfrage kommt, und es nötig ist einen neuen TcpClient zu erstellen.

Wenn der neue TcpClient erstellt ist, kannst mit dem machen was du willst. (Einen neuen Thread starten der den neuen User 'betreut' oder dergleichen). Und die Schleife beginnt von vorne.

Code:
IPAddress localIP = IPAdress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(localIP,5000); // lauschen auf Port 5000
listener.Start();

// IsRunning, nehmen wir an das ist eine boolsche Variable
// die angibt ob das Programm die Schleife auch ausfürehn soll.
// Nur ein True wäre dumm, da man dann die Schleife nicht
// so einfach beenden kann.
while (this.IsRunning) 
{
    TcpClient client = listener.AcceptTcpClient();
     this.MachWasMitDemNeuenUser(client);
}

So könnte das aussehen. Müsstest noch in VB.net übersetzen, Methoden und Klassen haben aber eh den selben Namen.

Mfg,
Alex
 
C# ist kein Problem.

Habs jetzt geschafft. Jetzt hat sich aber noch eine Frage wegen den Threads aufgetan. Ich möchte gerne für jeden Peer einen Thread anlegen, der ankommende Bytes liest.

Problem: Das Delegate ThreadStart, welches für Threads verwendet wird hat keine Parameter. Wie kann ich dem Thread einen Startparameter übergeben?
Ich habe dieses Problem mal über den ThreadPool gelöst. Soweit ich weiss besteht der aus ca. 25 Threads. Was nun, wenn ich mehr als 25 Peers habe?

Wie muss ich das machen?
 
Stimmt, beim Starten eines Threads hast du das Problem das du keine Parameter übergeben kannst. Da gibts einen kleinen Workaround könnte man sagen.

Erstelle eine Klasse welche im Konstruktor die gewünschten Parameter hat, und due gewünschte Funktionalität, also die Methode(n) welche als Thread gestartet werden sollen.

Wenn du dann einen neuen Thread für einen Peer erzeugen willst instanzierst du zuerst diese Klasse, weisst ihr die Parameter zu (den TcpClient, und am besten einen Verweis auf das Hauptprogramm, damit auf auf dessen Funktionen zugreifen kannst) und starte eine Methode davon als neuen Thread.

Code:
public class PeerClass
{
    public PeerClass(Form parent, TcpClient con)
    {
        //...
    }

    public void StartThread()
    {
        // tu was..
     }

}

....

while (this.IsRunning) 
{
    TcpClient client = listener.AcceptTcpClient();
    PeerClass pc = new PeerClass(this, client);
    Thread peerThread = new Thread(new ThreadStart(pc.StartThread));
    peerThread.Start();
}

So könnte das aussehen.

Mfg,
Alex
 
Geändert:
Ich habe es geschafft, Server und Clients inklusive Anmelden und Abmelden beim Server zu programmieren.
Eine Sache jedoch läuft nicht ganz zufriedenstellend: Wenn ich mit dem Client eine Verbindung zum Server aufbaue und diese Verbindung nachher wieder zerstöre ist der benutzte Anschluss (Port) immer noch besetzt.

Ich habe sowohl den NetworkStream wie auch den TcpClient über Close() beendet. Versuche ich weiterhin mit diesem Objekt zu arbeiten, erhalte ich natürlich die ObjectDisposedException

Wieso sind die Ports trotzdem nicht freigegeben? Wird der Client beendet und neu gestartet läuft alles wieder wunderbar.

Wie muss ich vorgehen um diesen Client endgültig zu killen?
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück