Laden...

Server handelt mit mehrere Clients gleichzeitig auf einem Port

Erstellt von snoopy vor 18 Jahren Letzter Beitrag vor 18 Jahren 2.926 Views
S
snoopy Themenstarter:in
204 Beiträge seit 2005
vor 18 Jahren
Server handelt mit mehrere Clients gleichzeitig auf einem Port

Hi,
wie ist es in .NET möglich, das ein TCP Server (TcpListener) auf Port z.B. 1400 läuscht und mit sagen wir mal 10 Clients gleichzeitig arbeiten kann. So das sich also 10 Clients gleichzeitig mit dem Server verbinden können.

Habe das damals in C mit der Funktion select getan. Nur die konnte ich nicht im .NET finden. Zudem möchte ich eigentlich keine Sockets nutzen, sondern den Network Stream zur Datenverarbeitung nutzen. Ist das möglich oder muss man beim Server auf einen Socket zurückgreifen? Ich hab zwar eine Möglichkeit mit Asyncsockets gefunden, doch wie gesagt, ich würde lieber ohne Sockets arbeiten. Wie realisiert ihr das?

4.221 Beiträge seit 2005
vor 18 Jahren

Ja das geht problemlos

mit TCPListener und TcpClient

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

S
snoopy Themenstarter:in
204 Beiträge seit 2005
vor 18 Jahren

Ja aber wie geht das mit einem TCPListener das sich mehrere Clients gleichzeitig auf dem selben Port mit dem Server verbinden. Wie z.B. ein FTP Server. Dort können sich ja auch so und so viele Clients gleichzeitig drauf verbinden.
Vielleicht mal nen kleines code Stückchen oder nen Howto oder sonstiges.

210 Beiträge seit 2005
vor 18 Jahren

Also im Grunde funktioniert das so, dass der TcpListener an einem bestimmten Port initialisiert wird. Auf diesem Port horcht der dann, ob Clients connecten wollen. Wenn dies der Fall ist, wird mit AcceptTcpClient() ein TcpClient-Object zurückgeliefert (das Accept... kann man im einfachsten Fall dann in einer Endlosschleife laufen lassen). Den TcpClient kannst du dann z.B. in einen Netzwerkstream verpacken.
Also das wichtigste in einem Satz: Die Clients bauen die Verbindung nicht mit dem TcpListener direkt auf, sondern jeder Client bekommt "seine eigene Conection".

Ausführliches Beispiel: MSDN

Blog

Portable WebDAV Library

Windows Server Advanced Power Management
Erweitertes Energie-Management unter Windows

S
8.746 Beiträge seit 2005
vor 18 Jahren

Jeder TCPListener im eigenen Thread....

1.985 Beiträge seit 2004
vor 18 Jahren

Hallo,

jetzt noch eine Frage, weil ich neu in dem Gebiet bin und mich das interessiert: Wo liegt der Vorteil in der oben von exec beschriebenen Methode? Warum keine Verbindung über Sockets?
Was von beiden ist besser oder anders gefragt: Wann bevorzuge ich welche Methode?

Danke und Gruß,
Fabian

"Eine wirklich gute Idee erkennt man daran, dass ihre Verwirklichung von vornherein ausgeschlossen erscheint." (Albert Einstein)

Gefangen im magischen Viereck zwischen studieren, schreiben, lehren und Ideen umsetzen…

Blog: www.fabiandeitelhoff.de

S
8.746 Beiträge seit 2005
vor 18 Jahren

Der TCPClient arbeitet nur synchron, während die Sockets auch asychrone Funktionen haben.

Darüberhinaus sind Sockets schneller. Der TCPClient hat dafür nette Features wie Timeout-Handling.

Unter dem TCPClient liegen Sockets..... der TCPClient stellt sowas wie ein High-Level-Interface für TCP dar, Sockets sind low-level.

Ist also Mächtigkeit/Performance (Sockets) gegen Komfort (TCPClient).

S
snoopy Themenstarter:in
204 Beiträge seit 2005
vor 18 Jahren

@svenson wenn ich jeden tcplistener in einen eigenen thread verpasse.. dann hab ich ja für jeden client einen eigenen port. was ja ziemlcih doof ist. will ja nur ein port aber viele clients.

S
snoopy Themenstarter:in
204 Beiträge seit 2005
vor 18 Jahren

@exec: Hab das jetzt mal versucht. aber so kann ja auch nur maximal ein Client sich verbinden. Erst wenn sich der Client trennt, wartet der server auf einen neuen client der sich wieder verbindet.


public TcpListener tl;
		public NetworkStream ns;
		public StreamWriter sw;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.TextBox status_text;
		public StreamReader sr;

	
		//static int anzahl_clients = 10;

		

		public main_form()
		{
			//
			// Erforderlich für die Windows Form-Designerunterstützung
			//
			InitializeComponent();
			tl = new TcpListener(1400);
			tl.Start();

			while(true)
			{
				TcpClient tc = tl.AcceptTcpClient();
				ns = tc.GetStream();
				sw = new StreamWriter(ns);
				sr = new StreamReader(ns);
				sw.WriteLine("du bist verbunden");
				sw.Flush();
			}
			
			
			//
			// TODO: Fügen Sie den Konstruktorcode nach dem Aufruf von InitializeComponent hinzu
			//
		}

ich möchte aber das sich mehere Clients gleichzeitig mit dem Server binden auf dem selben Port.

210 Beiträge seit 2005
vor 18 Jahren

Mit dem Port hat das ganr nichts zu tun. Auf dem Port "klopfen" die Clients nur am TcpListener an. Die daraufhin aufgebaute Verbindung hat mit dem Port nichts mehr zu tun (alle gehen über den gleichen Port).
Zum Codebeispiel: Jede Clientbehandlung im eigenen Thread.

Blog

Portable WebDAV Library

Windows Server Advanced Power Management
Erweitertes Energie-Management unter Windows

S
snoopy Themenstarter:in
204 Beiträge seit 2005
vor 18 Jahren

also sollte ich


	while(true)
			{
				TcpClient tc = tl.AcceptTcpClient();
				ns = tc.GetStream();
				sw = new StreamWriter(ns);
				sr = new StreamReader(ns);
				sw.WriteLine("du bist verbunden");
				sw.Flush();
			}

diesen Code Teil jeweils in einen eigenen Thread verpacken?
Aber wie? Dann brauch ich doch ein Event, was ausgelöst wird, falls ein Client neu verbindet und das event mir dann einen neuen Thread erstellt.

Ein Array von Threads kann man ja auch nicht in C# erstellen, oder?

jedenfalls klappt folgendes nicht:

Thread t[10];

@exec hast du mal irgendwo nen beispiel code wie sowas aufgebaut ist bzw genau funktioniert ?

P
939 Beiträge seit 2003
vor 18 Jahren

Der Code, der nach Aufbau der Verbindung Daten aus dem Stream empfängt, muss in einen eigenen Thread, nicht die ganze Schleife. Die erforderlichen Codezeilen zum Erstellen und Starten des Threads können direkt nach der Zeile mit TcpListener.AcceptTcpClient eingefügt werden. Es werden also keine Events oder ähnliches benötigt.

Ablauf:

  • Schleife wartet auf Verbindung (AcceptTcpClient blockiert).
  • Schleife nimmt Verbindung an.
  • Datenübertragung über Verbindung erfolgt in neuem Thread.
  • Schleife wartet schon auf die nächste Verbindung.

Thread t[10];

Programmierst du sonst C?
Der Arraytyp ist Thread[]. Eine Größe kann bei einer Array-Definition nicht angegeben werden, erst bei der Initialisierung. Und den Bezeichner so dazwischenklemmen geht auch nicht. 😉

Also so ist es richtig:

Thread[] t = new Thread[10];

Gruss
Pulpapex

S
snoopy Themenstarter:in
204 Beiträge seit 2005
vor 18 Jahren

Ja ich komme aus der C welt 🙂

Hab das jetzt mit 3 Threads versucht. Einmal der Mainthread wo die MainMethode drin ist. zur darstellung des Fensters. Ein Thread der nur Verbindungen annimmt und ein Thread für jeden Client zur verarbeitung. Nur wie übergebe ich dem 3. Thread nen Parameter auf das tcplistener Objekt ??


public Thread Hauptthread;
		public Thread[] clients;
		public bool status = true;

		public void vHaupthread()
		{
			while(status==true)
			{
				TcpClient tc = tl.AcceptTcpClient();
				clients[0] = new Thread(new ThreadStart(VerarbeiteClient(tc)));
				
			}
		}	
		public void VerarbeiteClient(TcpClient pTC)
		{
			ns = pTC.GetStream();
			sw = new StreamWriter(ns);
			sr = new StreamReader(ns);
			sw.WriteLine("du bist verbunden");
			sw.Flush();
		}



		public main_form()
		{
			//
			// Erforderlich für die Windows Form-Designerunterstützung
			//
			InitializeComponent();
			tl = new TcpListener(1400);
			tl.Start();
			Hauptthread = new Thread(new ThreadStart(this.vHaupthread));
			Hauptthread.Start();	
			//clients = new Thread[10];
			
			//
			// TODO: Fügen Sie den Konstruktorcode nach dem Aufruf von InitializeComponent hinzu
			//
		}

Wäre der Rest sonst so richtig ?

M
456 Beiträge seit 2004
vor 18 Jahren

Vom Prinzip her ja, aber du must den ClientThread natürlich noch starten. 😉
Außerdem musst du sicherstellen, dass der eingegangene Client auch an den Thread übergeben wird.

Du kannst da noch ne extra Klasse erstellen, die das kapselt (hier mal mit Sockets):


...
while(run)
{
	Socket s = socket.Accept();
				
	WorkerThread thread = new WorkerThread();
	thread.Start(s);
}
...
public class WorkerThread
{
	private Socket socket;
	private Thread thread;
		
	public WorkerThread()
	{
		thread = new Thread(new ThreadStart(WorkerThreadProc));
	}
		
	public void Start(Socket s)
	{
		socket = s;
		thread.Start();
	}
		
	private void WorkerThreadProc()
	{
	... 
	// client bedienen
	socket.Close();
	}
...

I am Jack's smirking revenge.
I am Jack's raging bile duct.
I am Jack's cold sweat.
I am Jack's complete lack of surprise.
I am Jack's broken heart.
I am Jack's wasted life.

S
snoopy Themenstarter:in
204 Beiträge seit 2005
vor 18 Jahren

Außerdem musst du sicherstellen, dass der eingegangene Client auch an den Thread übergeben wird.

hm ja das habe ich ja vor. Nur suche ich halt eine Möglichkeitkeit, parameter dem Thread zu übergeben. In C ist das kein Problem, da brauch ich keine extra Klasse für. Geht das nicht in C# auch ohne Klasse?

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo snoopy,

ohne Klasse geht es m.E. nicht, aber ohne extra Klasse eigentlich schon:

Parameter bei Threads

herbivore

S
snoopy Themenstarter:in
204 Beiträge seit 2005
vor 18 Jahren

hab es jetzt mit ner extra klasse gemacht. funktioniert auch einwandfrei. Danke schön allen.

M
456 Beiträge seit 2004
vor 18 Jahren

Ich möchte hier noch hinzufügen, dass es im .NET Framework 2.0 möglich ist auch Parameter direkt an den Thread zu übergeben:

http://msdn2.microsoft.com/library/1h2f2459(en-us,vs.80).aspx

I am Jack's smirking revenge.
I am Jack's raging bile duct.
I am Jack's cold sweat.
I am Jack's complete lack of surprise.
I am Jack's broken heart.
I am Jack's wasted life.