none
TCPClient Verbindung funktioniert nur noch mit installierten Visual Studio RRS feed

  • Frage

  • Ich bin inzwischen am verzweifeln.

    Das Programm was ich seit einiger Zeit sehr intensiv programmiere hat einen merkwürdigen Fehler. Es ist eine 1 Server - x Client Anwendung.

    Ich habe schon viele Versionen mit anderen Leuten getestet. Es hat alles so funktioniert wie es sollte. Nachdem ich mehrere Dutzend Stunden programmiert habe ohne mit jemand Aussenstehenden zu testen ist es passiert.

    Der Client vom Kumpel verliert die Verbindung zum Server.
    Bei mir hat es immer noch funktioniert.

    An diesem Problem hänge ich jetzt schon seit einer Woche. Ich habe keine Ahnung was ich groß an Quellcode in diesem Fall schicken soll. Also hier ein paar Fakten:

    - Ich benutze TCPClient und TCPListener
    - Programm funktioniert nur auf Computern mit Visual Studio (3/3)
    - Programm funktioniert auf Computern ohne Visual Studio nicht(6/6)
    Aktuelles Framework ist zumindest in ein paar von den 6 Fällen vorhanden
    - Der Client meldet den Exception "System.InvalidOperationException: Der Vorgang ist für nicht verbundene Sockets unzulässig." immer an folgender Stelle:

    byte[] bb = new byte[450];
    int k = stm.Read(bb, 0, 450); <--

    (stm = Socket)
    - Die Verbindung wird aufgebaut ... geht allerdings quasi sofort verloren
    - Senden funktioniert problemlos. (Kommt auch am Server an)

    Ich bin absolut ratlos. Ich weiß leider nicht woran es liegt, weil ich halt längere Zeit nicht mit anderen Leuten getestet habe. Ist auch das 1. Mal das mir sowas passiert. Stocher momentan nur noch im Dunkeln.

    Jetzt die Frage. Weiß jemand woran es liegen kann? Was könnte dafür sorgen, dass wenn Visual Studio mit C# installiert ist das Programm 100% funktioniert und ohne das Empfangen von Nachrichten nicht möglich ist.

    Quellcode weiß ich wie gesagt nicht was ich da schicken sollte :S. Es hat wie gesagt auch schon bei Leuten ohne Visual Studio funktioniert. Ich wüßte allerdings nicht was jetzt groß der Unterschied sein sollte.

    Vielen Dank fürs Lesen ...

    Sonntag, 14. Oktober 2012 20:26

Antworten

  • Hallo Jan,

    Ich werde mir dein Code im Laufe des morgigen Vormittags näher ansehen, obwohl ich schon jetzt kaum glauben kann, dass er so lauffähig ist.

    Eine Sache fällt mir aber gleich beim ersten Lesen auf: Dein Stream-Referenz-Feld (stm), wo wird es denn überhaupt initialisiert? Ich sehe, dass Du eine neue Instanz von TcpClient bei jedem Aufruf von Connect() erstellst (?), aber wo rufst Du denn tcpClient.GetStream() auf um stm zu initialisieren (wenn Du das im Konstruktor machst, brauchst Du dich über die Exception nicht weiter zu wundern).

    Auch sehe ich im Code viele notdürftig abgesicherten Feld-Variablen wie z.B. connected und viele lose Punkte, die ins Nirvana verweisen, wie z.B. die Hintergrundthreads oder der Hauptthread der unmittelbar nach einer UI-Anweisung - für mich nicht nachvollziehbar - schlafen geschickt wird.

    Über ein StackTrace würde ich mich dennoch freuen.

    Aber das wär dann alles fürs erste.

    Gruß
    Marcel

    • Als Antwort markiert Schockster Dienstag, 16. Oktober 2012 16:03
    Montag, 15. Oktober 2012 16:35
    Moderator

Alle Antworten

  • Hallo,

    vorab: die Existenz von Visual Studio hat mit dem Funktionieren von  TCP Sockets nun gar nichts zu tun.
    Nur das .NET Framework, in der von Dir verwendeten Version sollte installiert sein; wäre es das nicht, würde das Programm gar nicht erst starten.

    Einfluss auf TCP-Netzwerkverbindugen haben vor allem die Windows Firewall oder andere Wächter wie Virenscanner. Auch die Netzwerkkonfiguration, wie Router, Proxies uam. haben Einfluss darauf. Andere Dinge sind wackelige Netzwerkverbindungen - in der Zahl eher unwahrscheinlich.

    Als weitere Quelle kämen Programmierfehler. Die kann man aber anhand Deines Zweizeilers beim besten Willen nicht identifizieren.

    Gruß Elmar

    Montag, 15. Oktober 2012 07:08
    Beantworter
  • Hallo,

    Soll das heißen, dass die Anwendung nur innerhalb von Visual Studio läuft? - Wenn das so wäre, dann würde ich vermuten, dass eine deiner Referenzen in Zusammenhang mit der Herstellung der Verbindung warum auch immer den Gültigkeitsbereich verlassen hat. Unter Umständen hält der Debugger Referenzen noch am Leben, bzw. optimiert diese nicht weg. Ich habe dieses Verhalten auch im Zusammenhang mit Socket-Verbindungen auf separaten Threads im Debugger schon gesehen.

    Gruß
    Marcel

    Montag, 15. Oktober 2012 08:56
    Moderator
  • Erstmal vielen Dank für die Antworten

    @Elmar

    Ich kann mir eben nicht vorstellen, dass Visual Studio einen Einfluss darauf hat, aber es ist die einzige Gemeinsamkeit! Bei 6 Testpersonen ohne funktioniert es nicht und bei 3 Personen mit Visual Studio funktioniert es.

    Es wäre ein riesen Zufall wenn es an den Firewalleinstellungen, Virenscanner oder sonst was liegt
    Die Testpersonen haben es selbst schon den Server über localhost gestartet und mit dem Client verbunden. Ich gehe der Sache trotzdem mal nach. Ich meine viel Optionen gibt es ja nicht. Achja und eine ältere Version hatte ja mal bei allen funktioniert. Würde ja dann aussagen, dass es am Quellcode liegen muss. Aber wieso funktioniert es dann immer noch bei 1/3? Sprich denen die Visual Studio installierrt haben, es aber nicht darüber starten ....

    @Marcel

    Gute Idee. Ich habe gerade nochmal getestet, allerdings läuft es bei mir auch ohne durch Visual Studio gestatet zu sein. Das macht es natürlich logisch (zumindest für mich) unmöglich, dass es an Visual Studio liegt ....

    Allgemein:

    Also woran kann es liegen? Wenn es ein Programmierfehler wäre, wieso sollte es dann bei 1/3 der Testpersonen funktionieren? Framework war auch bei paar Testpersonen genau die gleiche wie ich sie habe. Ich kann mir halt nicht vorstellen, was der Quellcode hier helfen könnte. Ich kann natürlich trotzdem mal schauen, dass ich das wichtigste zusammenstelle.

    Nur ist es wirklich möglich, dass es am Programmcode liegt? Wäre das erste Mal das ich sowas mitbekomme. Vielleicht sollte ich mal eine VM aufsetzen.

    Gruß Jan

    • Bearbeitet Schockster Montag, 15. Oktober 2012 12:32 Verbesserung
    Montag, 15. Oktober 2012 12:21
  • Hallo Jan,

    Code zu posten wäre natürlich schon mal ein Anfang, aber zwischenzeitlich könntest Du bitte Exception.StackTrace und Exception.TargetSite protokollieren und posten? Ebenfalls: Könntest Du versuchen, die Socket-Timeouts hochzusetzen?

    Und noch etwas: Was ist stm.Read(), meintest Du stm.Receive()? Für mich sieht stm in deinem Code eher nach einem NetworkStream aus.

    Gruß
    Marcel

    Montag, 15. Oktober 2012 13:27
    Moderator
  • Hallo Marcel,

    momentan habe ich leider keinen Zugriff auf einen Computer auf dem es zu einem Fehler kommt. Zumindest kann ich schon mal mit Quellcode dienen.

    FrmMain.cs

    private void ConnectToServer(int port)
            {
                if (myClientManager.Connect(IPAddress.Parse(userData.GetLastIP()), port, version,
                    userData.GetName(), userData.GetFontColor() + "#" + userData.GetBackColor() + "#"))
                {
                    SwitchControlElements(true);
                    System.Threading.Thread.Sleep(100);                
                    receiveThread.Start();
                }
            } private void Receive() { ArrayList commandList; while (myClientManager.ClientConnected()) { if (myClientManager.Receive()) { } else { commandList = myClientManager.GetCommands(); myClientManager.ResetClientCommandsList(); if (commandList.Count > 0) { for (int k = 0; k < commandList.Count; k++) { DealMessages(commandList[k].ToString()); } } } } }

    ClientManager.cs

    public bool Connect(IPAddress ip, int port, string version, string name, string color)
            {
                myClient = new Client(ip, port);
                if (myClient.Connect())
                {
                    SendConnectInformation(port);
                    ThreadSendStatus.Start();
                    SendVersion(version);
                    SendName(name);
                    SendColor(color);
                    return true;
                }
                return false;
            }
    
    public bool Receive()
            {
                return myClient.Receive();
            }
    Client.cs


    Stream stm;
    TcpClient tcpClient;
    
    public bool Receive()
            {
                try
                {
                    if( connected)
                    {
                        stm.ReadTimeout = 10;
                        String text = "";
                        byte[] bb = new byte[450];
                        int k = stm.Read(bb, 0, 450);
                        for (int i = 0; i < k; i++)
                        {
                            text += Convert.ToString(Convert.ToChar(bb[i]));
                        }
                        //MessageBox.Show("Anfang Verarbeitung");
                        if (text == "")
                            return false;
                        else
                        {
                            commands.Add(text);
                            return true;
                        }
                    }
                    return false;
                } 
                catch(Exception exp)
                {
                    MessageBox.Show(exp.ToString());
                    //CloseConnection();
                    //connected = false;
                    return false;
                }   
            }
    
    public bool Connect()
            {
                try
                {
                    tcpClient = new TcpClient();
                    tcpClient.Connect(ipAd, port);
                    connected = true;
                    return true;
                }
                catch (Exception exp)
                {
                    MessageBox.Show("Es konnte keine Verbindung mit " + ipAd + ":" + port.ToString() + " aufgebaut werden!");
                    return false;
                }
            }

    Der Fehler taucht dann direkt beim ersten Receive auf...

    Gruß Jan



    • Bearbeitet Schockster Montag, 15. Oktober 2012 15:31
    Montag, 15. Oktober 2012 15:29
  • Hallo Jan,

    Ich werde mir dein Code im Laufe des morgigen Vormittags näher ansehen, obwohl ich schon jetzt kaum glauben kann, dass er so lauffähig ist.

    Eine Sache fällt mir aber gleich beim ersten Lesen auf: Dein Stream-Referenz-Feld (stm), wo wird es denn überhaupt initialisiert? Ich sehe, dass Du eine neue Instanz von TcpClient bei jedem Aufruf von Connect() erstellst (?), aber wo rufst Du denn tcpClient.GetStream() auf um stm zu initialisieren (wenn Du das im Konstruktor machst, brauchst Du dich über die Exception nicht weiter zu wundern).

    Auch sehe ich im Code viele notdürftig abgesicherten Feld-Variablen wie z.B. connected und viele lose Punkte, die ins Nirvana verweisen, wie z.B. die Hintergrundthreads oder der Hauptthread der unmittelbar nach einer UI-Anweisung - für mich nicht nachvollziehbar - schlafen geschickt wird.

    Über ein StackTrace würde ich mich dennoch freuen.

    Aber das wär dann alles fürs erste.

    Gruß
    Marcel

    • Als Antwort markiert Schockster Dienstag, 16. Oktober 2012 16:03
    Montag, 15. Oktober 2012 16:35
    Moderator
  • Hallo Jan,

    da geht es mir wie Marcel - so funktioniert er nur bei Vollmond ;)

    Der Code sieht ziemlich zusammengeklaubt aus, so wohl Teile aus:
    Introduction to TCP client server in C#
    (was schon nicht die beste gute Grundlage ist)

    Anstatt den Flickenteppich weitere Patches zu verpassen, wäre es besser, Du beschreibst, was Dein Programm am Ende tun soll. Dann könnte man einen Neuanfang wagen.

    Gruß Elmar


    Montag, 15. Oktober 2012 16:55
    Beantworter
  • Hallo,

    irgendwie ist "tcpClient.GetStream()" aus dem Konstruktur in die SendMethode gerutscht. Habe da allerdings gar nicht genauer nach dem Fehler gesucht, weil ich da dachte gar nichts geändert zu haben.

    Mit der Änderung jedenfalls funktioniert das Programm auch wieder auf allen Computern.

    Ich war halt naiv genug zu glauben, dass es ein anderen Grund geben kann ... Ist eben das erste Mal, dass ein Programm nur auf einen Teil der PC's läuft. Direkt auf 3 Computern, wo Visual Studio installiert ist und es nicht über selbiges gestartet wird, funktioniert es. Das ist dann also totaller Zufall? Ist ja mal interessant zu wissen.

    Darüber hinaus würde es mich natürlich interessieren, was genau das Problem sein soll bei dem momentanen Code. Ich verstehe vor allem nicht wie man aus den Code-Snippet erkennen kann, dass etwas ins Leere läuft.

    (Netzwerk)Anforderungen:

    Der Server wird als Chatserver benutzt und gleichzeitig verarbeitet er Daten von den Clients und verschickt sie wiederrum an die Clients. Das ist auch der aktuelle Stand, welcher jetzt wieder problemlos auf allen Computern funktioniert.

    Bis auf weiterer Informationsbearbeitung und Syncronisation zwischen den Clients wäre eine Dateiübertragung später zumindest nützlich.

    Irgendwie komme ich mir jetzt doof vor angesichts des doch schon blöden Fehlers, allerdings wirklich kompetente Hilfestellung von euch beiden.

    Wenn der Code wirklich so furchtbar ist sollte ich mich dann wohl doch mal genauer einlesen und eine Überarbeitung auf die ToDo Liste setzen. Für den Moment bin ich erstmal glücklich, dass alles wieder funktioniert und das Programm benutzt werden kann.

    Gruß Jan

    Dienstag, 16. Oktober 2012 12:07
  • Hallo Jan,

    schön das zumindest ein Verursacher geklärt ist.

    Bei den verbleibenden Dingen fängt es mit dem Dekodieren der Zeichen an. Richtig wäre es einen Decoder zu verwenden, siehe UnicodeEncoding.GetDecoder-Methode

    Denn es zum ersten ist es nicht gesagt, dass eine Nachricht in einem Block übertragen wird. Sie kann durchaus fragmentiert in mehreren Teilen eintreffen. Und Deine "Commands" wären dann zerstückelt.

    Wobei das nur eine der direkt auffälligen Stellen ist. Es dürfte sich noch einiges mehr finden lassen. Da Du bereits auf Codeproject gestöbert hast: Dort gibt es weitere TCP Chat Programme - wobei nicht alle alles richtig machen.

    Gruß Elmar

    Dienstag, 16. Oktober 2012 12:54
    Beantworter
  • Hallo Jan,

    Ende gut alles gut? - Nach meiner kurzen gestrigen Code-Review war es ja recht wahrscheinlich, dass etwas mit tcpClient.GetStream() nicht stimmte.

    Allerdings, wenn der Aufruf im Konstruktor der Klasse Client erfolgen sollte, d.h. *vor* der Instanziierung von tcpClient und *vor* dem Aufruf der Methode tcpClient.Connect(), würde ich nicht verstehen, warum dein GetStream() aus dem Konstruktor keine NullReferenceException im ersten und keine InvalidOperationException im zweiten Fall auslöst (wie das in der Dokumentation von TcpClient.GetStream() nachzulesen ist).  

    Kein Grund sich "doof" vorzukommen. Was glaubst Du, wie oft ich mir selber an die Stirn klatsche?

    ;-)

    Gruß
    Marcel

    Dienstag, 16. Oktober 2012 14:04
    Moderator