Laden...

Datentransfer über TCP Socket

Erstellt von Geraldo23 vor 19 Jahren Letzter Beitrag vor 19 Jahren 18.727 Views
G
Geraldo23 Themenstarter:in
19 Beiträge seit 2004
vor 19 Jahren
Datentransfer über TCP Socket

Hallo!
Ich habe folgendes Problem: Ich programmiere gerade ein Windows Service welches auf einem Exchange Server läuft und auf einem bestimmten Port wartet und dort XML Streams entgegennimmt und diese dann auswertet und Kontakte am Exchange Server anlegt. Also das funktioniert mit einer kleinen Menge an Daten, sobald ich aber eine große Menge an Daten schicke möchte funktioniert es nicht mehr, ich vermute mal dass das Service den XML Stream schneller ausdwertet als die Daten da sind, daher bekomme ich immer die Fehlermeldung dass sich ein ungültiges Zeichen im Stream befindet.
Wenn ich das Service jedoch am Localhost teste funktioniert alles.

Hier ist der Listen Code des Services:


protected void StartListen()
{
Console.WriteLine("Working Thread: {0} ",Thread.CurrentThread.Name);
	objSocket = listener.AcceptSocket();
	NetworkStream ns = new NetworkStream(objSocket);
	StreamReader sr = new StreamReader(ns);

                while(true)
	{
	         if(objSocket.Connected)
		{					
		StringBuilder objStrBuilder = new StringBuilder();					
		byte[] byteReceived = new byte[1024];
 //Es können jedoch auch mehr Daten übertragen werden
					
	                 Int32 nReceived = objSocket.Receive(byteReceived,byteReceived.Length,0);
		objStrBuilder.Append(System.Text.Encoding.ASCII.GetString(byteReceived,0,nReceived));
					
		EndPoint ep = objSocket.RemoteEndPoint;
		string ip = ep.ToString();
				
		while(!(nReceived<byteReceived.Length))
		{
		nReceived = objSocket.Receive(byteReceived,byteReceived.Length,0);
						                         objStrBuilder.Append(System.Text.Encoding.ASCII.GetString(byteReceived,0,nReceived));
		}

		string noError = "Erfolgreich empfangen";
		Byte[] message = System.Text.Encoding.ASCII.GetBytes(noError.ToCharArray());
		objSocket.Send(message,message.Length,0);
					
		Console.WriteLine("Nachricht von " + ip + " erhalten!");				
					
		checkXML(objStrBuilder); 
//dort wird der XLM Stream ausgewertet	
		}
		else
		{
		string error = "Keine Verbindung";
		Byte[] errorMsg = System.Text.Encoding.ASCII.GetBytes(error.ToCharArray());
		objSocket.Send(errorMsg,errorMsg.Length,0);
		}
	}			
}

An was könnte das liegen und wie könnte ich das Problem lösen?
Vielen Dank für eure Hilfe!

Mfg
Geri

R
139 Beiträge seit 2004
vor 19 Jahren

also das mit stream ist generell sone sache, würde ich nicht empfehlen (haste ja gesehen). andere gründe könnten auch zb unterbrechungen sein.

erstellt doch ein tmpXmlDatei die du dann nach erfolgreichen erhalt (kann auch zb durch validation erzielt werden muss aber nicht) erst DANN auswertest.

gruß,

r00t

posted by the real prince of persia

S
18 Beiträge seit 2004
vor 19 Jahren

sagen wir mal es kommen 2000 zeichen rein :

Int32 nReceived = objSocket.Receive(byteReceived,byteReceived.Length,0);

dann steht in nReceived <-- 1024

dann ergibt

while(!(nReceived<byteReceived.Length))

false weil (nReceived<byteReceived.Length) gleich true ist
da 1024 == 1024 heisst also für dateien unter 1kb klappt es
.. drüber nicht

Ci@o SCO

Debuggers dont remove bugs, they only show them in slow-motion.

R
139 Beiträge seit 2004
vor 19 Jahren

byte[] byteReceived = new byte[1024];
//Es können jedoch auch mehr Daten übertragen werden

ich habe das so verstanden als wenn auch 1024 Zeichen abgeschickt werden, und deswegen kommen auch 1024 an. "Es können jedoch auch mehr Daten übertragen werden".

@scordo
das was du das schreibst müßte dann auch für den localhost gelten...

posted by the real prince of persia

G
Geraldo23 Themenstarter:in
19 Beiträge seit 2004
vor 19 Jahren

Es steht nicht fest wieviele Daten geschickt werden. Wie kann ich das am besten realisieren dass das Service Daten entgegennimmt ohne eine bestimmte Größe festlegen zu müssen?

Die Methode checkXML soll erst aufgerufen werden wenn wirklich alle Daten da sind.

S
18 Beiträge seit 2004
vor 19 Jahren

ich habe das so verstanden als wenn auch 1024 Zeichen abgeschickt werden, und deswegen kommen auch 1024 an. "Es können jedoch auch mehr Daten übertragen werden".

genau das ist es ja .. wenn 2000 zeichen geschickt werden dann werden beim ersten senden 1024 zeichen übertragen und beim 2. mal 976 Zeichen. Er steigt aber schon beim ersten mal aus weil die while-bedinguing nicht greift.

Ci@o SCO

Debuggers dont remove bugs, they only show them in slow-motion.

S
18 Beiträge seit 2004
vor 19 Jahren

wenn es dir weiterhilft :

download

dort findest du von mir geschriebene Klassen (Server + Client) die haben events fürs connecten .. disconnecten .. receiven usw.

Ci@o SCO

Debuggers dont remove bugs, they only show them in slow-motion.

R
139 Beiträge seit 2004
vor 19 Jahren

wieso hast du das so programmiert?

  1. Lösung: schicke wirklich nur deine 1024 bytes ab
  2. Lösung: mach das mit der TmpXmlFile
  3. Lösung: while(!(nReceived<1))
  4. evtl. Lösung: du änderst diese zeile
    objSocket.Receive(byteReceived); // byte[] byteReceived = null;

Wenn ich das Service jedoch am Localhost teste funktioniert alles.

und warum funktioniert das trotzdem?

gruß,

r00t

posted by the real prince of persia

C
65 Beiträge seit 2004
vor 19 Jahren

Auf dem localhost dürfte es deswegen funktionieren, weil dort keine Leitungsprobleme (Collisions, Delays, Timeouts) auftreten. Das sieht in einem realen Netz ganz anders aus.

Wenn die MTU < 1024 steht, dann kommen nie 1024 Bytes auf einmal an, sondern immer maximal das, was in der MTU definiert ist. (MTU = maximum transmission unit, dazu eine gute Erklärung von D. Ruf.) Das ist zwar nicht üblich, aber aus welchem Grund auch immer kann das durchaus so sein. Außerdem beachte man das "M", sprich: trotz MTU von 1518 oder 1492 kann es passieren, dass IP-Pakete fragmentiert werden.

Die Lösung besteht also darin, den Socket so lange auszulesen, bis nix mehr kommt bzw. bis die Gegenstelle die Verbindung schließt bzw. bis man ein Timeout auslöst bzw. er eine Ausnahme wirft. Ansonsten Zustimmung zur obigen Aussage, dass Streams "böse" sind.

/// <summary>
/// Signatur
/// </summary>

R
139 Beiträge seit 2004
vor 19 Jahren

Original von CarstenP
Auf dem localhost dürfte es deswegen funktionieren, weil dort keine Leitungsprobleme (Collisions, Delays, Timeouts) auftreten. Das sieht in einem realen Netz ganz anders aus.

zuerst mal thx für die nette info.

bei localhost sollte doch erst recht der fehler auftauchen sollte weil wegen der relative "reibungslosen" transmission. oder?

gruß, r00t

posted by the real prince of persia

C
65 Beiträge seit 2004
vor 19 Jahren

Warte, habe ich Stuss erzählt? Ich hasse sinnfreie Verneinung in logischen Ausdrücken. Moment... 🤔

while(!(nReceived<byteReceived.Length))

<=>

while (nReceived ≥ byteReceived.Length)

(">" kann nicht sein, also...)

<=>

while (nReceived == byteReceived.Length)

d.h.: Solange immer der gesamte Buffer beim Lesen gefüllt wird, geht es weiter. Der Socket kriegt also z.B. 1518 Bytes - 14 Bytes Ethernet-Header - 4 Bytes Prüfsumme - 40 Bytes TCP-Header = 1460 Bytes Nutzdaten.

Davon werden 1024 an den Buffer übergeben, und asynchron wird der Socket wieder auf 1024 aufgefüllt usw., bis über den Socket alles geholt ist. Der letzte Block ist dann < 1024, und die while-Schleife endet.

Zur Prüfung meiner o.g. "Theorie" sollte man im Code die 1024 mal auf was richtig Großes verändern und mit dem localhost testen. Das kann dann fehlschlagen, muss es aber nicht, weil die Daten lokal ja huschhusch übertragen werden. Deswegen sollte man noch einen zweiten Test fahren mit einer sehr kleinen Paketgröße (64 Bytes oder sowas) und dann übers Netz probieren.

Schlauer wäre es natürlich, den Unfug zu lassen und das Auslesen des Sockets gleich richtig zu schreiben, also darauf zu prüfen, ob der Socket noch Daten kriegt.

/// <summary>
/// Signatur
/// </summary>

S
18 Beiträge seit 2004
vor 19 Jahren

generell sind die NetzworkStreams nicht wirklich zu empfehlen, in den meisten Fällen sollte man doch lieber auf die Low-Level-Socket-Implementierung zurück greifen und sich selbst was vernünftiges schreiben.

Is aber nicht so einfach da bei den Basis-Komponenten wirklich nur das nötigste implementiert ist und man ziemlich viel wissen bzw. sich anlesen muss um diese zu gebrauchen.

Ci@o SCO

Debuggers dont remove bugs, they only show them in slow-motion.

C
65 Beiträge seit 2004
vor 19 Jahren

Original von Scordo
generell sind die NetzworkStreams nicht wirklich zu empfehlen, in den meisten Fällen sollte man doch lieber auf die Low-Level-Socket-Implementierung zurück greifen und sich selbst was vernünftiges schreiben.

Is aber nicht so einfach da bei den Basis-Komponenten wirklich nur das nötigste implementiert ist und man ziemlich viel wissen bzw. sich anlesen muss um diese zu gebrauchen.

Jeppa, völlige Zustimmung. Das Framework gaukelt einem vor, IP wäre so schmuck einfach, dass das ein Kinderspiel sei, aber denkste. Ich würde mal sagen, wer noch keinen kleinen Server, der über IP arbeitet, in C geschrieben hat, inklusive fork() und solchen Späßen, wird sich auch mit dem Framework schwer tun, wenn er eine stabile, zuverlässige und performante Lösung entwickeln will.

/// <summary>
/// Signatur
/// </summary>