C# Backgroundworker



  • Hallo,

    Ich habe vor ein Chat-Client zu basteln, wo ich jetzt vor ein Problem stehe.
    Und zwar, wenn man im Chat drinne ist (Form), dann soll man ja durch den Server dauerhaft Nachrichten emopfangen können, ohne das der Client Blockiert.

    Mit dem Backgroundworker geht das ja, aber wie ist die frage?
    bei mir hängt sich der Client auf, wenn der einmal den Backgrtoundworker durchlaufen ist.

    Hier der Code:

    private void frmChat_Load(object sender, EventArgs e)
            {
                bgwChat = new BackgroundWorker();
                bgwChat.WorkerSupportsCancellation = true;
                bgwChat.WorkerReportsProgress = true;
                bgwChat.DoWork += new DoWorkEventHandler(bgwChat_DoWork);
    
                bgwChat.RunWorkerAsync();
            }
    
    private void bgwChat_DoWork(object sender, DoWorkEventArgs e)
            {
                string tempnachricht = "";
    
                // Empfange-Text
                netz.empfangsocket();
                string empfange = netz.ausgabesocketrec();
    
                for (int i = 0; i < empfange.Length; i++)
                {
                    if (empfange.Substring(i, 1) == "=")
                    {
                        tempnachricht = empfange.Substring(i, empfange.Length - i);
                    }
                }
    
                if (empfange.Length > 1)
                {
                    richTextBoxchat.SelectedRtf = empfange + "\n";
                }
            }
    

    Vielleicht weiß einer von euch, was da ich machen kann, oder bzw eine andere Möglichkeit.

    mfg



  • PS: die Funktion ist noch net fertig (Nicht wundern) 🙂



  • b4nan1 schrieb:

    Mit dem Backgroundworker geht das ja, aber wie ist die frage?
    bei mir hängt sich der Client auf, wenn der einmal den Backgrtoundworker durchlaufen ist.

    Nunja, zum einen ist es nicht korrekt, das du in DoWork auf die GUI zugreifst. - Dafür gibt es z.B. ReportProgress. Der Empfangsthread friert solang ein, bis neue Nachrichten kommen, das ist so schon korrekt.



  • Gibt es denn eine andere Möglichkeit das zu lösen? z.B dll in dauerschleife?



  • Dein Empfangsthread sollte schon eine Dauerschleife sein, bis die Verbindung getrennt wird. Zugriffe auf die GUI jedoch sollten wie schon gesagt synchronisiert werden z.B. beim Backgroundworker über ReportProgress.



  • b4nan1 schrieb:

    Gibt es denn eine andere Möglichkeit das zu lösen? z.B dll in dauerschleife?

    Es spielt keine Rolle in welcher Assembly eine Methode sich befindet, sie wird immer im Thread des Aufrufers ausgeführt.

    Dauerschleife und Threading sind schon die richtigen Stichwörter. Wobei ich sowas direkt mit der Klasse Thread und nicht dem Backgroundworker angehen würde.



  • Liegt das vielleicht an mein sockets, das der mein Backgroundworker blockiert?
    Habe auch noch Funktionen wo ich die sockets benutze, und die immer abrufe wegen den Status.



  • Starte das Programm im Debugger und schau dir an, welche Anweisung blockiert.

    Setze also einen Breakpoint auf die öffnende Klammer von bgwChat_DoWork().
    Starte das Programm im Debugger.
    Geh das Programm in Einzelschritten durch.
    F11 springt in aufgerufene Methoden hinein, so dass Du die auch untersuchen kannst.

    Wenn Du dann auf eine blockierende Socket.Read() oder ähnliche Anweisung stößt, dann ist das innerhalb eines BackgroundWorkers in Ordnung. Er wird halt nichts an den Hauptthread melden, solange keine Daten ankommen.

    Aber den Zugriff auf richTextBoxchat aus bgwChat_DoWork heraus ist nicht Ok. Das gehört in bgwChat_ReportProgress http://msdn.microsoft.com/en-us/library/a3zbdb1t.aspx.

    Und natürlich muss DoWork eine Schleife sein, die läuft, solange CancellationPending http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.cancellationpending.aspx nicht gesetzt ist.



  • Hallo,

    Der hängt sich bei der Socket Geschichte auf, hier mal der komplette Code von der Klasse:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    using System.ComponentModel;
    
    // Sockets
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    
    namespace Chat_Vegas
    {
        public class Netzwerk
        {
            private static Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint IPENDP = new IPEndPoint(IPAddress.Parse("25.111.38.123"), 11000);
            BackgroundWorker bg = new BackgroundWorker();
    
            // Schalter für Chat
            bool ChatOn = false;
    
            public Netzwerk()
            {
                bg.DoWork += new DoWorkEventHandler(bg_DoWork);
                bg.RunWorkerAsync();
            }
    
            public void bg_DoWork(object sender, DoWorkEventArgs e)
            {
                string ausgabe;
                byte[] buffE = new byte[128];
    
                while (true)
                {
                    // Schalter
                    if (ChatOn == true)
                    {
                        try
                        {
                            int RecByte = socket.Receive(buffE);
    
                            ausgabe = null;
    
                            ausgabe = ASCIIEncoding.ASCII.GetString(buffE, 0, RecByte);
                            ergebnis2 = ausgabe;
                            // leereergebnis();
                            Array.Clear(buffE, 0, buffE.Length);
                        }
                        catch (Exception)
                        {
    
                        }
                    }
                 }
            }
    
            // Ergebnis Empfang
            private string ergebnis1;
            private string ergebnis2;
    
            // Schalter setzen
            public void chatschalter()
            {
                ChatOn = true;
            }
    
            // Socket connect
            public void connectsocket()
            {
                socket.Connect(IPENDP);
            }
    
            // Socket schließen
            public void closesocket()
            {
                socket.Close();
            }
    
            // Socket-send-text
            public void sendesocket(string sende)
            {
                byte[] buffer = ASCIIEncoding.ASCII.GetBytes(sende);
                socket.Send(buffer);
                Array.Clear(buffer, 0, buffer.Length);
            }
    
            // Socket-send-file
            public void sendfile(string filename)
            {
                socket.SendFile(filename);
            }
    
            // Socket empfange
            public void empfangsocket()
            {
                byte[] buffE = new byte[128];
                int RecByte = socket.Receive(buffE);
                auswertensocketempfang(buffE, RecByte);
                Array.Clear(buffE, 0, buffE.Length);
            }
    
            // Socket-empfange-auswerten
            public void auswertensocketempfang(byte[] buf, int Rec)
            {
                string ausgabe;
                ausgabe = null;
                ausgabe = ASCIIEncoding.ASCII.GetString(buf, 0, Rec);
                ausgabesocketempfang(ausgabe);
            }
    
            // Socket empfang zuweisen
            public void ausgabesocketempfang(string er)
            {
                ergebnis1 = "";
                ergebnis1 = er;
                // return ergebnis;
            }
            //
    
            // Socket empfang-ausgabe1
            public string ausgabesocketrec1()
            {
                return ergebnis1;
            }
    
            // Socket empfang-ausgabe2
            public string ausgabesocketrec2()
            {
                return ergebnis2;
            }
    
            // Ergebnis Leeren
            public void leereergebnis()
            {
                ergebnis1 = "";
            }
    
            // Instance
            public static Socket GetInstance()
            {
                return socket;
            }
        }
    }
    

    Und hier der Code, wo der sich aufhängt, wenn ich die Form betrete:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    // Sockets
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    
    namespace Chat_Vegas
    {
        public partial class frmChat : Form
        {
            Socket socket = Netzwerk.GetInstance();
            Netzwerk netz = new Netzwerk();
            User user = User.GetInstance();
    
            public frmChat()
            {
                InitializeComponent();
            }
    
            private void frmChat_Load(object sender, EventArgs e)
            {
                // Schalter setzen (Chat)
                netz.chatschalter();
    
                //timerchat.Interval = 150;
                // timerchat.Start();
            }
    
            private void frmChat_FormClosing(object sender, FormClosingEventArgs e)
            {
                string sendleave = "<LeaveChannel>";
                netz.sendesocket(sendleave);
            }
    
            private void txtbchatsend_KeyPress(object sender, KeyPressEventArgs e)
            {
                if (e.KeyChar == 13)
                {
                    string sendtext = "<SendMessage=" + user.zeigenick() + "," + this.Text + ",'" + txtbchatsend.Text + "'>";
                    netz.sendesocket(sendtext);
                    txtbchatsend.Text = ""; 
                }
            }
    
            private void timerchat_Tick(object sender, EventArgs e)
            {
                richTextBoxchat.SelectedRtf = netz.ausgabesocketrec2() + "\n";
            }
        }
    }
    


  • Und in DoWork bei:

    int RecByte = socket.Receive(buffE);
    

    Hängt der, wo ich sagen muss, da ich den mal bei einloggen benuzt habe, und da hat er nicht blockiert, nur wenn ich die Chatfrm betrete, und den da nutze.



  • Für die Zukunft:
    Bitte markiere interessante Stellen im Code, z.B. per Kommentar. Die Zeile

    int RecByte = socket.Receive(buffE);
    

    kommt mehrmals vor. Und die Stelle in Deiner Form ist überhaupt nicht auffindbar.

    Für jetzt:
    Hier http://msdn.microsoft.com/en-us/library/8s4y8aff.aspx steht, dass das Blockieren bei Receive(byte[]) normales Verhalten ist. Die Anweisung kehrt erst zurück, wenn der Puffer voll ist.

    Teste das, indem Du dem Socket Daten zum Lesen zur Verfügung stellst. Blockiert er immernoch, nachdem Daten in der Größe des Puffers empfangen worden sind?


Log in to reply