Laden...

C# Mehrere Netzwerkkarten Traffic Routing HttpClient?

Erstellt von CSharpFreak vor 9 Jahren Letzter Beitrag vor 9 Jahren 5.697 Views
C
CSharpFreak Themenstarter:in
42 Beiträge seit 2014
vor 9 Jahren
C# Mehrere Netzwerkkarten Traffic Routing HttpClient?

Hallo -

ich frage mich ob es möglich ist den Traffic meiner Anwendung auf eine bestimmte Netzwerkkarte umzulenken? Für die Kommunikation nutze ich die 'HttpClient' Klasse.
Ich habe bisher nichts brauchbares finden könne, vielen Dank.

MfG

C
2.121 Beiträge seit 2010
vor 9 Jahren

Mehrere Netzwerkkarten hat man normalerweise mit mehreren verschiedenen Netzwerken. Jede Karte ist für eines zuständig.
Um die zu unterscheiden muss zum Beispiel jedes Netzwerk ein eindeutiges Subnetz haben. Dann werden die Anfragen an eine IP über die zuständige Karte geroutet.

Wenn du jetzt eine bestimmte Karte haben willst, schließe ich daraus du willts die Anfrage in dem bestimmten Subnetz haben? Das sollte eigentlich von selbst richtig passieren, vorausgesetzt das ist alles richtig konfiguriert.

Falls das nicht hilft solltest du genauer erklären was du vor hast.

C
1.214 Beiträge seit 2006
vor 9 Jahren

Das wäre normalerweise nichts, was die Anwendung selber entscheidet, das entscheidet der Administrator. Unter Linux würdest du das mit iptables definieren, unter Windows mit route.

Sowas kann durchaus Sinn machen, auch wenn die beiden Netzwerkkarten mit dem gleichen Netzwerk verbunden sind. Stell dir vor, du hast zwei Möglichkeiten ins Internet rauszukommen, eine schnell und teuer, die andere nicht so schnell, dafür aber eine billige Standleitung. Für bestimmte Dienste willst du die schnelle Verbindung nutzen, für den Rest die andere.

C
CSharpFreak Themenstarter:in
42 Beiträge seit 2014
vor 9 Jahren

So ist es -
Die Karten im PC besitzen jeweils ihr eigenes Subnet, welche ebenfalls ihren eigenen Internetanschluss haben. Nun möchte ich einer C# .Net Anwendung sagen welche Karte sie nutze soll um ins Internet zu kommen. Momentan wird der weg eher zufällig vom System gewählt (nimmt scheinbar den momentan am besten geeigneten Ausgang).

MfG

1.696 Beiträge seit 2006
vor 9 Jahren

Hallo,

wenn man über alle Karten ins Internet kommen kann, kannst du nicht gezielt eine Karte nehmen, es sei denn du baust dir eine Routing-Tabelle dermaßen aus, dass bestimmte Adresse über bestimmte Karte "raus kommt", etwa so:

sei Karte a (IF 1) mit ip 10.1.1.5 und Karte b (IF 2) mit 10.1.2.5 und du möchtest für alle Ziele im Bereich 123.456.789.0/24 über Karte a gehen, sonst über b, mit:

route add 123.456.789.0 mask 255.255.255.0 10.1.1.5 metric 10 if 1
route add 0.0.0.0 mask 0.0.0.0 10.1.2.5 metric 10 if 2

sollte es dann gehen

Grüße

edit: route add -p => permanent, d.h. auch nach dem booten des PC bleibt die Routing erhalten.

Ich bin verantwortlich für das, was ich sage, nicht für das, was du verstehst.

**:::

C
CSharpFreak Themenstarter:in
42 Beiträge seit 2014
vor 9 Jahren

Vielen Dank - Das Routing in Windows ist nicht mein Problem.. eher das Routing in der C# .Net Anwendung wie ich sage das er die IP nehmen soll.

MfG

1.696 Beiträge seit 2006
vor 9 Jahren

Tja, dann musst du mit Socket & Co arbeiten und die Verbindung komplet "händisch" auf- und abbauen. Was hast du gegen routing über der Einstellung von Betriebssystem?

Grüße

Ich bin verantwortlich für das, was ich sage, nicht für das, was du verstehst.

**:::

C
2.121 Beiträge seit 2010
vor 9 Jahren

Vielleicht soll das Routing nicht an IPs hängen sondern am Zweck der Verbindung, so wie Coder007 mutmaßt.
Dann könnte es sein dass die Anwendung zwei Anfragen an die selbe IP über verschiedene Karten verschicken soll.

C
CSharpFreak Themenstarter:in
42 Beiträge seit 2014
vor 9 Jahren

Danke für eure Hilfe - Ich habe es nun mit Hilfe des SerivePointManager's erfolgreich lösen können.

Mir ist jedoch eine Sache aufgefallen, wenn man "WebRequest" mit "HttpClient" vergleicht ist die "WebRequest" um einiges schneller... wie kommt es zu diesem Effekt?

Habe mich beim Test auf diesen Thread bezogen (Antwort von Abt).

MfG

16.833 Beiträge seit 2008
vor 9 Jahren

Schau Dir mal den HttpClient genau an, dann wird Dir auffallen, dass das Ding quasi ein Browser ohne Oberfläche ist; natürlich mit dementsprechenem Umfang.
Ein WebRequest ist nur dazu da, dass er Inhalte abruft. Also zwei völlig verschiedene Werkzeuge, die natürlich in ihrer Eigenschaft auch andere Performancewerte erzeugen.

C
CSharpFreak Themenstarter:in
42 Beiträge seit 2014
vor 9 Jahren

Vielen Dank für den Hinweis - Ich habe mir jetzt mal genauer angeschaut... hätte ich lieber mal anfangs direkt geschaut hätte ich mir viel arbeit ersparen können, Danke.

B
218 Beiträge seit 2012
vor 9 Jahren

Schau Dir mal den HttpClient genau an, dann wird Dir auffallen, dass das Ding quasi ein Browser ohne Oberfläche ist; natürlich mit dementsprechenem Umfang.

HttpClient ist doch nur ein Wrapper um den WebRequest und kein Browser. Schneller ist der meiner Meinung nach auch nicht. Im Gegenteil, verbraucht nur mehr Threads.

Hab deinen Code mal abgeändert:

private static void Main(string[] args)
		{
			Do();
			Console.ReadKey();
		}

		private static async Task Do()
		{
			var httpClient = new HttpClient();
			ServicePointManager.DefaultConnectionLimit = 100;

			var sw = Stopwatch.StartNew();
			var tasks = Enumerable.Range(0, 100).Select(x => SendRequestAsync(x, httpClient));
			Task.WaitAll(tasks.ToArray());
			Console.WriteLine("Duration Limit 2: " + sw.Elapsed.TotalSeconds);
			ServicePointManager.DefaultConnectionLimit = 2;

			sw = Stopwatch.StartNew();
			Parallel.ForEach(Enumerable.Range(0, 100), x => SendRequest(x, 2));
			Console.WriteLine("Duration Limit 2: " + sw.Elapsed.TotalSeconds);

			sw = Stopwatch.StartNew();
			Parallel.ForEach(Enumerable.Range(0, 100), x => SendRequest(x, 100));
			Console.WriteLine("Duration Limit 100: " + sw.Elapsed.TotalSeconds);
		}

		private static async Task SendRequestAsync(int i,HttpClient httpClient)
		{
			Console.WriteLine("SEND " + i);

			var response = await httpClient.GetStringAsync(@"http://www.microsoft.com/");

			Console.WriteLine("END " + i);
		}

		static void SendRequest(int i, int limit)
		{
			Console.WriteLine("SEND " + i);

			var wrq = (HttpWebRequest)WebRequest.Create(@"http://www.microsoft.com/");
			var wr = (HttpWebResponse)wrq.GetResponse();
			wrq.ServicePoint.ConnectionLimit = limit;
			using (var ds = wr.GetResponseStream())
			{
				var response = new StreamReader(ds, Encoding.UTF8).ReadToEnd();
			}

			Console.WriteLine("END " + i);
		}

16.833 Beiträge seit 2008
vor 9 Jahren
  1. da steht "quasi Browser" und nicht "Browser" - irgendwie muss man es Laienhaft erklären....
  2. Das Ding verbraucht keine Threads, sondern Ressourcen. Threads kann man nicht verbrauchen sondern nur nutzen und mehrere Threads hat das Ding auch nicht. Wenn überhaupt arbeitet das Ding mit mehrere Tasks.
var tasks = Enumerable.Range(0, 100).Select(x => SendRequestAsync(x, httpClient));
Task.WaitAll(tasks.ToArray());

Nicht wirklich "gut."
Wenn schon so eine relativ schmutzige Lösung, dann

var tasks = Enumerable.Range(0, 100).Select(x => SendRequestAsync(x, httpClient));
var result = await Task.WhenAll(tasks.ToArray());

ansonsten gehen Dir mögliche Exceptions flöten.

B
218 Beiträge seit 2012
vor 9 Jahren

await Task.WaitAll

?

16.833 Beiträge seit 2008
vor 9 Jahren

Sollte WhenAll heissen.Ist korrigiert.

B
218 Beiträge seit 2012
vor 9 Jahren

WhenAll liefert nur einen Task zurück, keinen Task<T>.

Von Verbrauchen kann man meiner Meinung nach schon sprechen. Wenn man davon ausgeht, dass ein Thread in etwa ~1MB RAM benötigt und man somit auf einem PC mit 1GB RAM arbeitet, hat man von den 1000 möglichen Threads 100 verbraucht.

16.833 Beiträge seit 2008
vor 9 Jahren

Bitte richtig lesen. Ansonsten ist das hier alles Käse.
How to: Extend the Async Walkthrough by Using Task.WhenAll (C# and Visual Basic)


public static Task<TResult[]> WhenAll<TResult>(
	IEnumerable<Task<TResult>> tasks
)

Soviel zum Thema..

WhenAll liefert nur einen Task zurück, keinen Task<T>.

Von Verbrauchen kann man meiner Meinung nach schon sprechen. Wenn man davon ausgeht, dass ein Thread in etwa ~1MB RAM benötigt und man somit auf einem PC mit 1GB RAM arbeitet, hat man von den 1000 möglichen Threads 100 verbraucht.

Zeigt mir jetzt, dass Du den Unterschied von Tasks und Threads nicht wirklich verstanden hast.
Wir arbeiten hier direkt nur mit Tasks und NICHT mit Threads. Die kümmern uns nicht UND wir müssen uns NICHT darum kümmern.

a) gibt es kein festes Limit von Threads. Diese werden durch die vorhandenen Ressourcen dynamisch ermitteln.
b) gibt es überhaupt kein Limit von Tasks.
Ein Thread kann Millionen von Tasks verwalten, aber jeder Task ist einem Thread zugeordnet.
Es ist also durchaus möglich (aber unwahrscheinlich), dass ein einziger Thread sich um alle Tasks einer Methode kümmern.
Das ist der riesen Vorteil von Tasks: man muss sich um die Ressourcen nicht kümmern.

Es ist korrekt, dass 1000 Threads erst mal 1000 MB Speicher allokieren.
Aber 1000 Tasks brauchen vielleicht 5MB. Ist komplett Ressourcen-unabhängig.

Du solltest Dir hier nochmal die Grundlagen von Tasks zu Gemüte führen 😉

16.833 Beiträge seit 2008
vor 9 Jahren

Ich hab dazu vor einiger Zeit mal eine Grafik gemacht, wie das funktioniert (war für Azubis konzipiert, sodass das Verständnis für die Einsteiger etwas leichter ist).
Es ist nicht 100%tig genau, weil es insgesamt schon etwas komplizierter ist (es fehlen zB Global und Local Queues, Queue Stealing etc...) - aber die Grundstruktur erklärt die Verwandtschaft von Tasks und Threads.

Ich habe die Grafik auch noch nicht Reviewen lassen!

B
218 Beiträge seit 2012
vor 9 Jahren


>

Eben und deswegen funktioniert dein Code so nicht, weil die übergebenen Tasks ein TResult zurückliefern müssen und SendRequestAsync kein Result liefert.

Klar ist mir der Unterschied zwischen Tasks und Threads bewusst. Ich sprach über Threads im Zusammenhang mit dem WebRequest. Der Parallel.ForEach Wrapper im Zusammenhang mit WebRequest legt mir jeden Request auf einen Thread. Es werden unnötig Threads verbraucht.

16.833 Beiträge seit 2008
vor 9 Jahren

Wenn Du jetzt den Code 1:1 meinst, dann funktioniert dieser nicht. Korrekt.
Nur was bringt Dir ein SendAsyncRequest, ohne das Resultat zu erhalten? In 99,9% der Fälle: nichts.

Wenn hier jetzt den Thread ein unbeteiligter sieht, der das Zeug nicht zum reinen Test nehmen will, sondern produktiv, dann braucht er i.d.R. das Resultat.
Und dann ist der Code eben mehr als nur suboptimal. Gib den SendAsyncRequest Task<String> und liefer das Response zurück, dann gehts.
Ich hatte - fälschlicherweise - angenommen, dass Dir diese Situation bewusst ist.

Der Parallel.ForEach Wrapper im Zusammenhang mit WebRequest legt mir jeden Request auf einen Thread. Es werden unnötig Threads verbraucht.

Diese Aussage ist pauschal absolut falsch.
Lass Dir zusätzlich die ThreadID ausgeben und Du wirst sehen, dass nur ca. 10-12 Thread die komplette Arbeit von 100 Tasks übernehmen. Die genaue Anzahl kommt auf die vorhandene Menge an (freier) Ressource an.
Das liegt am Task Scheduler und MaxDegreeOfParallelism, der nicht alle Tasks zeitgleich laufen lässt, die Parallel.ForEach erzeugt, auch wenn dessen Wert durch -1 die freie Skalierung zulässt. Es richtet sich immer noch an die verfügbaren Kerne.