Backgroundworker kann durch Socket nicht beendet werden



  • Hallo

    Ich habe ein kleine Programm geschrieben mit dem ich über eine TCP IP Verbindung Daten austausche. Prinzipiell funktioniert alles.
    Die Socket Verbindung baue ich in einem Backgroundjob auf.
    Das Problem-> dieser lässt sich nicht mehr stoppen.
    Grund ist die Socket Verbindung. Wenn ich die weg lasse kann ich den job auch sauber beenden.
    Aber wie beende oder lösche ich die Socketverbindung???
    Leider bekomm ich das nicht hin....

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                try
                {
                    // Connection 
                    byte[] data = new byte[numberOfBytestoRecieve];
                    IPEndPoint myIpep = new IPEndPoint(IPAddress.Any, myPort);
                    Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
                    newsock.Bind(myIpep);
                    newsock.Listen(10);
    
                    // *** Die nächste Zeile macht das Problem ***
                    Socket client = newsock.Accept();
                    //client.Disconnect(false);    // hilft alles nix
                    //client.Dispose();  // hilft alles nix
                    //client.Close();  // hilft alles nix
    
                   .......
                }
                catch (Exception ex)
                {
                   ...........
                }
            }
    
    		 private void button1_Click(object sender, EventArgs e) //START
            {
                try
                {
                    // start backgroundWorker1
                    backgroundWorker1.WorkerSupportsCancellation = true;
    
                    if (backgroundWorker1.IsBusy != true)
                    {
                        backgroundworker1Enable = true;
                        backgroundWorker1.RunWorkerAsync();
                        textBox1.Text = " Verbindungsaufbau gestartet ";
                        textBox2.Text = " ";
                    }               
                }
                catch (Exception ex) { throw; };
    
            }
    
    		private void button2_Click(object sender, EventArgs e) //STOP
            {
    
                if (backgroundWorker1.IsBusy == true)
                {
                    backgroundworker1Enable = false;
                    backgroundWorker1.CancelAsync();
                }
    
            }
    

    Danke



  • Hallo,

    mache 'newsock' zu einer Membervariablen und rufe darauf Shutdown() und Close() in deinem Button-Click auf, s.a. C# Stop Socket.Accept() oder http://stackoverflow.com/questions/452327/proper-way-to-stop-listening-on-a-socket



  • // *** Die nächste Zeile macht das Problem ***
      Socket client = newsock.Accept();
    //client.Disconnect(false);    // hilft alles nix
    //client.Dispose();  // hilft alles nix
    //client.Close();  // hilft alles nix
    

    newsock.Accept() gibt dir nur ein Socket zurück wenn auch eine Verbindungsanfrage vorliegt. Ansonsten wartet newsock.Accept() solange bis eine Verbindung kommt (newsock.Blocking = true) oder wirft eine Exception (newsock.Blocking = false).

    Wenn der Thread bei newsock.Accept() wartet bringts natürlich nichts irgendwas dahinter zu schreiben.

    Socket.BeginAccept eignet sich vielleicht besser:
    http://msdn.microsoft.com/en-us/library/5bb431f9.aspx



  • Hallo

    Danke für eure Antworten.
    'newsock' war das Problem.
    Mit folgendem Code funktioniert es .

    client.Shutdown(SocketShutdown.Both);
                        client.Disconnect(false);
                        client.Dispose();
                        newsock.Dispose();
    

    DANKE



  • Hallo

    Ich habe meinen Code etwas erweitert.
    Prinzipiell funktioniert auch alles:
    1. Ich starte die Applikation
    2. Ein zweites Programm sendet Daten, diese werden auch korrekt von mir empfangen
    3. Der Backgroundjob wird sauber beendet

    So weit so gut. Jedoch habe ich jetzt noch zwei "Problemfälle" an denen ich mir die Zähne ausbeiße:

    1. Ich den Backgrounfworker, es werden jedoch keine Daten gesendet. Wie kann ich dann den Backgroundworker stoppen? Da ist dann wieder mein ursprüngliches Problem.

    backgroundworker1Enable = false;
                        backgroundWorker1.CancelAsync();
    

    Funktioniert nicht!

    2. Nun möchte ich natürlich nicht nur einmal die Daten empfangen, sondern ständig. Wie macht man das Richtig?
    a. Über einen Timer der ständig immer wieder den Backgroundworker aufruft?
    b. Über eine "while(true)" Schleife?

    Anbei mein code:

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                try
                {
                    // Connection 
                    SetText1("Start DoWork routin in background....");
                    int myPort          = 2000;
                    byte[] data         = new byte[numberOfBytestoRecieve];
    
                    IPEndPoint myIpep   = new IPEndPoint(IPAddress.Any, myPort);
                    Socket newsock      = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
                    newsock.Bind(myIpep);
                    newsock.Listen(10);
                    SetText1(" Waiting for a client on Port " + myPort + " ...");
                    Socket client       = newsock.Accept();
    
                    SetText1("Start Listening .... ");
                    data = ReceiveData(client, numberOfBytestoRecieve);
                        for (int j = 0; j < numberOfBytestoRecieve; j++)
                        {
                            SetText1("Recieving Data ....");
                            int tmp = Convert.ToInt32(data[j]);
                            if (tmp != 0)
                            {
                                SetTextRecieveLog(tmp.ToString());
                                SetTextRecieveLog("j");
                            }
                        }
    
                        client.Dispose();
                        newsock.Dispose();
    
                }
                catch (Exception ex)
                {         ...            }
            }
            private static byte[] ReceiveData(Socket s, int size)
            {
                int total = 0;
                int dataleft = size;
                byte[] data = new byte[size];
                int recv;  
                while (total < size)
                {
                    recv = s.Receive(data, total, dataleft, 0);
                    if (recv == 0)
                    {
                        data = Encoding.ASCII.GetBytes("exit ");
                        break;
                    }
                    total += recv;
                    dataleft -= recv;
                }
    
                return data;
            }
    

    Beste Grüße



  • Kann mir da wirklich niemand weiterhelfen?
    Oder sind die Fragen zu trivial?

    Gruß



  • Du musst das Accept() in einer Schleife laufen lassen, also Lösung b).

    Du könntest dir das ganze Geraffel mit dem BGW und der Schleife auch sparen, wenn du den Vorschlag von Process annehmen und die ganze Kommunikation mit BeginXXX/EndXXX verarbeiten würdest. Du kannst dann über Events eine "Schleife" bauen.



  • Du musst das Accept() in einer Schleife laufen lassen, also Lösung b).

    Das werde ich mal versuchen.

    Aber was meinst du mit

    Du kannst dann über Events eine "Schleife" bauen.

    ???

    Gruß



  • Das sieht ungefähr so aus (ungetestet, sollte als Beispiel aber genügen):

    using System;
    using System.Data;
    using System.Text;
    using System.Windows.Forms;
    using System.Net;
    using System.Net.Sockets;
    
    namespace Server
    {
        public partial class ServerForm : Form
        {
            Socket serverSocket;
            byte[] byteData = new byte[1024];
    
            public ServerForm()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {            
                try
                {
                    serverSocket = new Socket(AddressFamily.InterNetwork, 
                                              SocketType.Stream, 
                                              ProtocolType.Tcp);
    
                    IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 1000);
                    serverSocket.Bind(ipEndPoint);
                    serverSocket.Listen(4);
    
                    // Hier der asynchrone Aufruf
                    serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
                }
                catch (Exception ex)
                { 
                    // ignore
                }            
            }
    
            private void OnAccept(IAsyncResult ar)
            {
                try
                {
                    Socket clientSocket = serverSocket.EndAccept(ar);
    
                    // Hier findet die "Schleife" ihre Anwendung und zwar durch rekursiven Aufruf von BeginAccept()
                    serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
    
                    clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), clientSocket);
                }
                catch (Exception ex)
                { 
    
                }
            }
    
            private void OnReceive(IAsyncResult ar)
            {
                try
                {
                    Socket clientSocket = (Socket)ar.AsyncState;
                    clientSocket.EndReceive(ar);
    
                    // Datan verarbeiten ...
    
                    // Und wieder durch rekursiven Aufruf weitere Daten empfangen
                    clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), clientSocket);
                }
                catch (Exception ex)
                { 
                }
            }
        } 
    }
    


  • Hallo

    Da das Ganze ja dauerhaft laufen soll habe ich folgenden Code nun innerhalb einer while(true) Schleife im BGW laufen lassen.

    // Hier der asynchrone Aufruf 
                    serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
    

    Ausführen kann ich den code. Aber die OnAccept Methode wird nur ein einziges mal beim starten aufgerufen. Danach nicht mehr. Auch wenn der Client weiterhin Daten sendet.

    Gruß



  • BeginAccept() dient dazu die Verbindung des Clients zu akzeptieren, mehr nicht. Um Daten vom Client empfangen zu können, benötigst du Begin-/EndReceive() (siehe mein Beispiel oben). Wenn du dich für asynchrone Aufrufe entscheidest, dann ist der BackgroundWorker überflüssig, das ist ja gerade der Vorteil.

    • Willst du an deinem bestehenden Code nicht viel Ändern, dann bleib beim BGW, setzt das Accept() in eine Schleife und führ das Receive solange aus, bis vom Client alle Daten abgeholt wurden
    • Willst du asynchron arbeiten, kann der BGW weg und du musst wie in meinem Beispiel vorgehen. (Einfach mal nach googlen)


  • Hi

    Ja, soweit (eigentlich) so klar. Ich war eben etwas voreilig mit Copy/Paste.

    Prinzipiell möchte ich gerne die Asynchrone Variante verwenden. Jedoch soll das gnaze nicht beim starten der Applikation angetriggert werden, sondern ich möchte mit einem Start und Stop Button das empfangen starten und stoppen.

    Wäre es daher sinnvoll die Verbindung wie in deinem Beispiel zu akzeptieren und dann in einem BGW die Daten zu empfangen?

    Gruß



  • Nein wäre es nicht. BeginXXX/EndXXX bringen ja den Vorteil, das das UI davon unbehelligt bleibt, da diese Methoden im Threadpool einen eigenen Thread anlegen. Um dem UI Änderungen zu vermitteln, musst du dann Dispatcher.Invoke() aufrufen.

    Du kannst den Code aus der Form_Loaded-Methode auch einfach in die Click-Methode des Start-Buttons einbauen.



  • Hallo

    U.a. habe ich mir mal folgenden Link angeschaut:
    http://msdn.microsoft.com/de-de/library/bbx2eya8(v=vs.80).aspx

    Ich glaube (hoffe) das Ganze so langsam zu verstehen. Benutze ich BeginnXXX/EndXXX wird der Callback in einem extra Thread bearbeitet. Benutze ich den BGW wäre das Doppelt gemoppelt.
    Morgen werde ich das ganze nochmals programmiertechnisch umzusetzen.
    Bei meiner Recherche bin ich auch auf folgenden Link gestoßen: http://www.codeplanet.eu/tutorials/csharp/4-tcp-ip-socket-programmierung-in-csharp.html?start=2
    Ist es zu empfehlen TcpClient und TcpListener zu verwenden?



  • Hallo

    Also ein Stück bin ich nun weiter.
    Ich habe mal folgendes versucht umzusetzen. Das ist ähnlich wie mir vorher geraten wurde. Prinzipiell funktionierts auch, jedoch wird durch die while(true) schleife meine Form blockiert.

    Wie kann ich das denn umgehen bzw verhindern?

    Anbei mal der Code:

    private void button1_Click(object sender, EventArgs e)
            {
                    StateObject myFinalStateobject  = new StateObject();
                    IPEndPoint ipEndPoint           = new IPEndPoint(IPAddress.Any  , myPort);
                    Socket mySocket                 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    StartListening(ipEndPoint);
    
            }
    
            public void StartListening(IPEndPoint localEP)
            {
                Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
                    listener.Bind(localEP);
                    listener.Listen(10);
    // Diese Schleife macht das Problem
                    while (true)
                    {
                        allDone.Reset();
                        listener.BeginAccept(new AsyncCallback(acceptCallback), listener);
                        if (allDone.WaitOne(2000)) { SetTextRecieveLog("Verbindung Erfolgreich aufgebaut! "); }
                        else { SetTextRecieveLog("Timeout Verbindungsaufbau" + localEP.ToString()); }
                    }
            }
    
            public void acceptCallback(IAsyncResult ar)
            {
                allDone.Set();
                Socket listener = (Socket)ar.AsyncState;
                Socket handler = listener.EndAccept(ar);
                // Additional code to read data goes here.  
                // Create the state object.
                StateObject state = new StateObject();
                state.workSocket = handler;
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(readCallback), state);
            }
    


  • Nun auch als Mitglied......



  • Mach die Schleife weg und ruf in acceptCallback() nochmals BeginAccept() auf. So erzeugst du wiederholtest die Abfrage von Client-Verbindungen.



  • Hi

    Mach die Schleife weg und ruf in acceptCallback() nochmals BeginAccept() auf. So erzeugst du wiederholtest die Abfrage von Client-Verbindungen.

    Die Lösung funktioniert leider nicht.

    Mitlerweile habe ich es hinbekommen.
    Den Socket habe ich doch schon. Daher muss ich doch irgendwie fortlaufend die BeginnReceive Methode aufrufen-

    Jedoch finde ich das das nicht so ne ganz saubere Lösung ist da meine Lösung eher Zeitgesteurt und nicht Ereignisgesteuert ist.

    Irgendwie muss es doch möglich sein die BeginnReceive Methode aufzurufen, direkt nach dem Daten empfangen wurden??? Ich habs schon mit

    receiveDone.WaitOne
    

    () versucht, aber das hat auch nicht funktioniert....

    Hier mal die zeitgesteuerte Lösung:

    public void acceptCallback(IAsyncResult ar)
            {
                allDone.Set();
                Socket listener = (Socket)ar.AsyncState;
                Socket handler = listener.EndAccept(ar);
    
                // Additional code to read data goes here.  
                // Create the state object.
                listener.BeginAccept(new AsyncCallback(acceptCallback), listener);
                StateObject state = new StateObject();
                state.workSocket = handler;
                while (true)
                {
                    receiveDone.Reset();
                    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(readCallback), state);
    
                    Thread.Sleep(1000);
                    if (myState.sb.ToString() != "") SetTextRecieveLog(myState.sb.ToString());
                    myState.sb.Clear();
                }
    
            }
    


  • Hi

    Da ich noch immer nicht so richtig weiter komme möchte ich meine Frage mal etwas konkreter stellen:

    Folgender Code:

    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(readCallback), state);
    

    Wenn ich das richtig verstanden habe wird doch readCallback nur aufgerufen nachdem wirklich Daten vom Client empfangen wurden? Oder nicht?

    Bei mir wird diese Funktion ständig aufgerufen wenn ich ein schleife um BeginRecieve mache...


Anmelden zum Antworten