Hallo zusammen,
wie ist der beste Weg eine automatische Reconnect Funktionalität bei einem TcpClient zu implementieren für den Fall dass die Verbindung abbricht (Netzwerkkabel gezogen, Server aus, etc)
Hier ein Aussschnitt aus meinem derzeigen code:
public void ClientWork()
{
TcpClient client = new TcpClient();
try
{
try
{
client.Connect(ip, port);
}
catch(Exception ex)
{
logger.ErrorFormat("client.Connect: {0}", ex.Message);
return false;
}
NetworkStream ns = client.GetStream();
byte[] buff;
while (__bRunning)
{
buff = new byte[1000];
ns.Read(buff, 0, 1000);
string line = System.Text.Encoding.Default.GetString(buff);
//tu was mit line...
}
//ns.Close();
client.Close();
}
catch(Exception e)
{
//Reconnect?
client.Close();
client = null;
return false;
}
}
Ein "normales" vorgehen wäre eventuell die Funktion mehrmals mit einem bestimmten Zeitabstand aufzurufen (Retrys + Maximum Retry Count).
Realisieren könntest du das ganze mit nem Timer der die Funktion wieder aufruft .. oder indem du die Funktion selbst wieder aufrufst ...
Der Vorteil der Klugheit liegt darin, dass man sich dumm stellen kann - umgekehrt ist das schon schwieriger (K. Tucholsky)
Das Problem mit Internet-Zitaten ist, dass sie oftmals zu unrecht als authentisch angenommen werden. (K. Adenauer)
ich hab mittlerweile nun was von polling gelesen. am besten in einem eigenen thread der immer wieder überpüft ob die verbindung noch am leben ist.
wir würde man das am besten realisieren?
Der Punkt ist, dass es eine "abgebrochene Verbindung" in dem Sinne nicht gibt. Es gibt eher "Timeouts". Insofern wird bei den Protokollen, bei denen eine dauerhafte Verbindung gehalten werden muss in der Regel "IDLE"-Kommandos implementiert. Beim IRC z.B. der "PING"-Befehl, auf den der Server mit "PONG" antwortet.
Insofern sendet man dann alle X Minuten diesen Befehl - und wenn nicht innerhalb von X Sekunden eine Antwort bekommt, dann schließt man die Verbindung und baut die Verbindung neu auf.
Transparent - also so "nebenher" ohne dass die restliche Anwendung davon etwas mitbekommt - funktioniert das ganze nicht.
würdest du dann einen extra (zb workerthread) machen der alle offenen verbindungen "pingt" und wenn eine nicht antwortet nach 10 sek dann diese zumacht und neu öffnet?
Im Prinzip muss man nicht mal eine Antwort von der Gegenstelle erhalten.
Wenn die Verbindung irgendwo unterbrochen ist, dann kann man genau einmal etwas ohne Fehler senden... beim nächsten Send gibts dann einen Laufzeitfehler.
Um bei Ping/Pong zu bleiben (kommt mir bekannt vor)...
Statt Ping kann man z.B: ein Ascii-Null oder irgendwas schicken (muss aber auf der Empfangsseite immer wieder rausgefriemelt werden)
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
Warum nicht eine Schicht tiefer gehen ?
Da braucht man keine ASCII zeichen.
Packete einfach in etwa so aufbauen:
1 Int32 => Size der nachfolgenden bytes
1 Byte => Packet ID
Byte[Size-1] => Rest
Durch die Packet ID kannst du dann z.b. entscheiden was es ist ob z.b. Chat, Ping, Pong oder was auch immer.
ich kann aber nicht entscheiden wie die pakete aussehen die ich empfange. darauf habe ich keinen einfluss...
In dem Fall kannst du nur warten, ob du Exceptions bekommst und dann die Verbindung neu aufbauen. Das wird dann aber erst nach einem vom Betriebssystem definierten Zeitraum sein.
Oder wenn du nur empfängst musst du halt selber einen Timeout definieren.
Du kannst nicht "eine Verbindung anpingen" oder sowas.
bedeutet ich muss an die stelle die ich im codeausschnitt schon mit //Reconnect?? markiert habe?
würdet ihr dann eine Rekursion an der Stelle machen oder wie das Wiederverbinden lösen?
Moin,
while(!ende)
{
if (!connected)
{
connectUnit();
} else {
readData();
}
}
private void readData()
{
try {
// Daten lesen
} catch(Exception ex) {
connected=false;
}
}
private void connectUnit()
{
try {
// Verbindung aufbauen
connected = true;
} catch(Exception ex) {
connected=false;
}
}
und einfach so geht nicht?
public void ClientWork()
{
TcpClient client = new TcpClient();
try
{
try
{
client.Connect(ip, port);
}
catch(Exception ex)
{
logger.ErrorFormat("client.Connect: {0}", ex.Message);
return false;
}
NetworkStream ns = client.GetStream();
byte[] buff;
while (__bRunning)
{
buff = new byte[1000];
ns.Read(buff, 0, 1000);
string line = System.Text.Encoding.Default.GetString(buff);
//tu was mit line...
}
//ns.Close();
client.Close();
}
catch(Exception e)
{
//Reconnect?
client.Close();
client = null;
ClientWork(); <<----???
return false;
}
}
Hallo!
@ratalert:
Wenn du dann aber ein größeres Netzwerk-Problem hast, kommst du ganz schnell an einen StackOverflow.
Nobody is perfect. I'm sad, i'm not nobody 🙁
vielleicht mit kurzem sleep dazwischen? irgendwie find ich nicht so die wirklich schöne lösung bei der ich nicht alles umbauen muss...
vielleicht mit kurzem sleep dazwischen?
lies bitte was ein StackOverflow ist und wie er funktioniert bzw. ausgelöst wird ... dann überlege nochmal ob Dir ein schnödes Sleep wirklich hilft
irgendwie find ich nicht so die wirklich schöne lösung bei der ich nicht alles umbauen muss...
ist schon Mist wenn man nochmal von vorne anfangen muss um es richtig zu machen
ist schon Mist wenn man nochmal von vorne anfangen muss um es richtig zu machen
Willkommen in der Wirklichkeit 😃
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
sehr ihr also keine lösung in meinen bestehenden code den reconnect noch einzubauen?
oder ihn so zu verändern dass ich ihn einbauen kann?
sehr ihr also keine lösung in meinen bestehenden code den reconnect noch einzubauen?
oder ihn so zu verändern dass ich ihn einbauen kann?
Wieso ? Hat das jemand behauptet ?
Das kriegst Du schon selber hin 😃 Im Prinzip kannst Du entscheiden welchen Tod du sterben willst... (im Moment wirst Du früher oder später einen StackOverflow kriegen)... Du könntest es so ändern, dass du den Caller nicht mehr aus der Methode rauslässt wenn es nicht funktioniert hat (dann stirbst Du den "Meine App hängt-Tod")
Oder du machst es sauber und wirfst Exception und behandelst das Problem beim Aufrufer.
Das Optimum dürfte irgendwo dazwischen sein... wenn Du die Daten nicht versenden kannst, dann versuche 1 mal die Verbindung ab und neu aufzubauen... und wenn das nicht funzt, dann wirfst Du Exception und behandelst diese beim Caller (um ein Hang zu vermeiden).
Und bitte ein wenig mehr Eigeninitiative sonst machen die lieben Kollegen den Thread hier schneller zu als Du aus dem Stack rausfliegst.
[Edit] Wer noch mehr Schreibfehler findet darf sie behalten[/Edit]
Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...
Hilfreich sind dabei sicherlich auch die asynchronen Methoden (Begin/EndConnect, Begin/EndRead, usw.)